示例#1
0
def show(main_window):
    """Show a system tray icon with a small icon."""
    _fix_unity_systray()
    icon = QIcon(multiplatform.get_path("encuentro/logos/icon-192.png"))
    sti = QSystemTrayIcon(icon, main_window)
    if not sti.isSystemTrayAvailable():
        logger.warning("System tray not available.")
        return

    def showhide(_):
        """Show or hide the main window."""
        if main_window.isVisible():
            main_window.hide()
        else:
            main_window.show()

    _menu = QMenu(main_window)
    _act = _menu.addAction("Mostrar/Ocultar")
    _act.triggered.connect(showhide)
    _act = _menu.addAction("Acerca de")
    _act.triggered.connect(main_window.open_about_dialog)
    _act = _menu.addAction("Salir")
    _act.triggered.connect(main_window.on_close)
    sti.setContextMenu(_menu)
    sti.show()
示例#2
0
文件: tray.py 项目: herlang/iosshy
class Tray(QObject):
    activated = pyqtSignal()

    def __init__(self, parent, title, icon):
        QObject.__init__(self)

        # Setup contextual menu
        if kde:
            self.menu = KMenu(parent)
            self.tray = KStatusNotifierItem(parent)
            self.tray.setStatus(KStatusNotifierItem.Passive)
            self.tray.setCategory(KStatusNotifierItem.ApplicationStatus)
            self.tray.setAssociatedWidget(parent)
            self.tray.setStandardActionsEnabled(False)
            self.tray.activateRequested.connect(self._activateRequested)
        else:
            self.menu = QMenu()
            self.tray = QSystemTrayIcon()
            self.tray.activated.connect(self._activated)
        self.setIcon(icon)
        self.setTitle(title)
        if not kde:
            self.tray.show()
        self.tray.setContextMenu(self.menu)

    def setActive(self, active=True):
        if kde:
            self.tray.setStatus(KStatusNotifierItem.Active if active else KStatusNotifierItem.Passive)

    def setTitle(self, title):
        if kde:
            self.tray.setTitle(title)
            self.tray.setToolTipTitle(title)
        else:
            self.tray.setToolTip(title)
        self.menu.setTitle(title)

    def setToolTipSubTitle(self, subtitle):
        if kde:
            self.tray.setToolTipSubTitle(subtitle)

    def setIcon(self, icon):
        if kde:
            self.tray.setIconByPixmap(icon)
            self.tray.setToolTipIconByPixmap(icon)
        else:
            self.tray.setIcon(icon)

    def showMessage(self, title, message, icon=None):
        if kde:
            self.tray.showMessage(title, message, "network-server")
        else:
            self.tray.showMessage(title, message, QSystemTrayIcon.Information if icon is None else icon)

    def _activated(self, reason):
        if reason == QSystemTrayIcon.DoubleClick:
            self.activated.emit()

    def _activateRequested(self, active, pos):
        self.activated.emit()
示例#3
0
def show(main_window):
    """Show a system tray icon with a small icon."""
    _fix_unity_systray()
    icon = QIcon(multiplatform.get_path("encuentro/logos/icon-192.png"))
    sti = QSystemTrayIcon(icon, main_window)
    if not sti.isSystemTrayAvailable():
        logger.warning("System tray not available.")
        return

    def showhide(_):
        """Show or hide the main window."""
        if main_window.isVisible():
            main_window.hide()
        else:
            main_window.show()

    _menu = QMenu(main_window)
    _act = _menu.addAction("Mostrar/Ocultar")
    _act.triggered.connect(showhide)
    _act = _menu.addAction("Acerca de")
    _act.triggered.connect(main_window.open_about_dialog)
    _act = _menu.addAction("Salir")
    _act.triggered.connect(main_window.on_close)
    sti.setContextMenu(_menu)
    sti.show()
示例#4
0
class SystemTrayRemoto(ServicoFuncao):
    def __init__(self, parent=None):
        super().__init__(5433, 5433, parent)
        
        self.systemTray = QSystemTrayIcon()
        self.systemTray.setIcon(QIcon("bad.svg"))
        self.systemTray.show()
    
    @send_funcao
    def ativar(self, titulo, mensagem):
        self.systemTray.showMessage(titulo, mensagem, QSystemTrayIcon.Information, 3000)
示例#5
0
文件: tray.py 项目: Kenishi/DroidNavi
class Tray():

    def __init__(self, parent):
        
        icon = AppIcon.getAppIcon()
        if icon:
            self.tray = QSystemTrayIcon(icon)
        else:
            self.tray = QSystemTrayIcon()
        self.parent = parent
        
        self.tray.setToolTip("Droid Navi")
        
        # Menu
        self.menu = QMenu()
        self.menu.addAction("Show Connected List", partial(self.maximize))
        self.menu.addAction("Options", partial(self.parent.openSettings))
        self.menu.addAction("Exit", partial(self.parent.close))
        self.tray.setContextMenu(self.menu)
        
        # Connect handlers
        self.tray.activated.connect(self.activated)
    
    def getTray(self):
        return self.tray
     
    def display(self, show):
        ''' Toggle showing the tray '''
        
        if show:
            self.tray.show()
        else:
            self.tray.hide()
    
    @pyqtSlot()
    def maximize(self):
        ''' Show the main window and hide tray icon '''
        
        self.display(False)
        self.parent.maximizeFromTray()
    
    @pyqtSlot()
    def activated(self, reason):
        if reason == QSystemTrayIcon.DoubleClick:
            self.maximize()
示例#6
0
class StartQT4(Windows):
	
	def keyPressEvent(self, event):
		k = event.key() 
		if k == QtCore.Qt.Key_Escape:
			sys.exit()
		elif k == QtCore.Qt.Key_Enter-1:
			self.ui.btnSend.clicked.emit(True)
			
	def __init__(self, parent=None):
		QtGui.QWidget.__init__(self, parent)
		self.ui = Ui_winMain()
		self.ui.setupUi(self)
		QtCore.QObject.connect(self.ui.btnSend, QtCore.SIGNAL("clicked()"), self.SendQuery)
		self.setMouseTracking(True)
		self.setWindowFlags(QtCore.Qt.FramelessWindowHint|QtCore.Qt.WindowStaysOnTopHint| Qt.Popup | Qt.Tool)
		
		# 创建托盘
		self.icon = QIcon("img.png")
		self.trayIcon = QSystemTrayIcon(self)
		self.trayIcon.setIcon(self.icon)
		self.trayIcon.setToolTip(u"simple有道")
		self.trayIcon.show()
		# 托盘气泡消息
		self.trayIcon.showMessage(u"simple有道", u"simple有道已经启动,随时待命!")
		# 托盘菜单
		self.action = QAction(u"退出simple有道", self, triggered = sys.exit) # 触发点击后调用sys.exit()命令,即退出
		self.menu = QMenu(self)
		self.menu.addAction(self.action)
		self.trayIcon.setContextMenu(self.menu)
		self.move(1100,50)
		#开启监听线程
		system("xclip -f /dev/null")           #清空剪切板
		listener = Thread(target=listenMouse, args=(self.ui,))
		listener.setDaemon(True)
		listener.start()
        
	def SendQuery(self):
		querystring = "http://fanyi.youdao.com/openapi.do?keyfrom=hustbg&key=1205943053&type=data&doctype=json&version=1.1&q="+unicode(self.ui.txtSend.text())
		response = json.loads(requests.get(querystring).text)
		try:
			result = u"   音标:"+response["basic"].get("phonetic","")+u"\n   翻译:"+u','.join(response["translation"])+u"\n   解释:\n   "+'\n   '.join(response["basic"]["explains"][0:2])
			self.ui.labresult.setText(result)
		except:
			self.ui.labresult.setText(u"没有查到相关记录")
示例#7
0
class Tray():
    def __init__(self, parent):

        icon = AppIcon.getAppIcon()
        if icon:
            self.tray = QSystemTrayIcon(icon)
        else:
            self.tray = QSystemTrayIcon()
        self.parent = parent

        self.tray.setToolTip("Droid Navi")

        # Menu
        self.menu = QMenu()
        self.menu.addAction("Show Connected List", partial(self.maximize))
        self.menu.addAction("Options", partial(self.parent.openSettings))
        self.menu.addAction("Exit", partial(self.parent.close))
        self.tray.setContextMenu(self.menu)

        # Connect handlers
        self.tray.activated.connect(self.activated)

    def getTray(self):
        return self.tray

    def display(self, show):
        ''' Toggle showing the tray '''

        if show:
            self.tray.show()
        else:
            self.tray.hide()

    @pyqtSlot()
    def maximize(self):
        ''' Show the main window and hide tray icon '''

        self.display(False)
        self.parent.maximizeFromTray()

    @pyqtSlot()
    def activated(self, reason):
        if reason == QSystemTrayIcon.DoubleClick:
            self.maximize()
示例#8
0
class sysBaloon(QMainWindow):
    def baloon(self, t, m, tm=50000):
        self.trayicon = QSystemTrayIcon(self)
        if self.trayicon.supportsMessages():
            icona = QIcon('py.ico')
            self.trayicon.setIcon(icona)
            self.trayicon.show()
            self.trayicon.showMessage(t, m, msecs=tm)
            time.sleep(10)
            self.trayicon.hide()
        else:
            print "This Function isn't supported."
            choose = raw_input("Would you enable it? Y/N \n --> ")
            if choose == "Y":
                shell = os.popen('enable_baloon.reg')
                print "Run again this program"
            elif choose == "N":
                print "You don't use this program without baloon enabled."
            else:
                print "You have insert wrong char."
class Example(QtGui.QMainWindow):

    
def __init__(self):
super(Example, self).__init__()


self.path=sys.path[0]
f=open('%s/ACCESS_KEY'% self.path,'r')
f1=open('%s/ACCESS_SECRET'% self.path,'r')
f2=open('%s/user_info'% self.path)
self.user_name=f2.readline().strip('\n')
self.user_id=f2.readline().strip('\n')
self.a=f.readline().strip('\n')
self.b=f1.readline().strip('\n')
f.close()
f1.close()
f2.close()
self.initUI()

def initUI(self):

self.icon=QSystemTrayIcon()
self.icon.isSystemTrayAvailable()
self.icon.setIcon( QtGui.QIcon('%s/web.png'% self.path) )
self.icon.setToolTip ( 'dubbleclick to maximize')
self.icon.show()
self.icon.activated.connect(self.activate)
self.setWindowFlags(QtCore.Qt.FramelessWindowHint)
                self.setAttribute(QtCore.Qt.WA_TranslucentBackground)
self.setGeometry(300, 300, 1500, 1000)
frame = QtGui.QFrame(parent=self)
                frame.setStyleSheet("QFrame {background: rgba(0,0,0,50%)}")
box=QtGui.QHBoxLayout()

self.edit = QtGui.QLineEdit()
         self.edit.setStyleSheet("background: rgba(0,0,0,100%); "" font-weight : bold;" "color: rgb(250,250,250);""border:5px solid ")
    def __init__(self, AUTO):
        ' Initialize QWidget inside MyMainWindow '
        super(MyMainWindow, self).__init__()
        QWidget.__init__(self)
        self.auto = AUTO
        self.statusBar().showMessage('               {}'.format(__doc__))
        self.setStyleSheet('QStatusBar{color:grey;}')
        self.setWindowTitle(__doc__)
        self.setWindowIcon(QIcon.fromTheme("face-monkey"))
        self.setFont(QFont('Ubuntu Light', 10))
        self.setMaximumSize(QDesktopWidget().screenGeometry().width(),
                            QDesktopWidget().screenGeometry().height())

        self.base = path.abspath(path.join(getcwd(), str(datetime.now().year)))

        # directory auto completer
        self.completer = QCompleter(self)
        self.dirs = QDirModel(self)
        self.dirs.setFilter(QDir.AllEntries | QDir.NoDotAndDotDot)
        self.completer.setModel(self.dirs)
        self.completer.setCaseSensitivity(Qt.CaseInsensitive)
        self.completer.setCompletionMode(QCompleter.PopupCompletion)

        # process
        self.process1 = None
        self.process2 = None
        self.cmd1 = 'nice -n {n} arecord{v} -f {f} -c {c} -r {b} -t raw'
        self.cmd2 = 'oggenc - -r -C {c} -R {b} -q {q} {d}{t}{a} -o {o}'
        self.process3 = QProcess(self)
        #self.process3.finished.connect(self.on_process3_finished)
        #self.process3.error.connect(self.on_process3_error)

        self.cmd3 = ('nice -n 20 ' +
          'sox "{o}" -n spectrogram -x {x} -y {y} -z 99 -t "{o}" -o "{o}.png"')
        self.actual_file = ''

        # re starting timers, one stops, one starts
        self.timerFirst = QTimer(self)
        self.timerFirst.timeout.connect(self.end)
        self.timerSecond = QTimer(self)
        self.timerSecond.timeout.connect(self.run)

        # Proxy support, by reading http_proxy os env variable
        proxy_url = QUrl(environ.get('http_proxy', ''))
        QNetworkProxy.setApplicationProxy(QNetworkProxy(QNetworkProxy.HttpProxy
            if str(proxy_url.scheme()).startswith('http')
            else QNetworkProxy.Socks5Proxy, proxy_url.host(), proxy_url.port(),
                 proxy_url.userName(), proxy_url.password())) \
            if 'http_proxy' in environ else None
        print((' INFO: Proxy Auto-Config as ' + str(proxy_url)))

        # basic widgets layouts and set up
        self.mainwidget = QTabWidget()
        self.mainwidget.setToolTip(__doc__)
        self.mainwidget.setMovable(True)
        self.mainwidget.setTabShape(QTabWidget.Triangular)
        self.mainwidget.setContextMenuPolicy(Qt.CustomContextMenu)
        self.mainwidget.setStyleSheet('QTabBar{color:white;font-weight:bold;}')
        self.mainwidget.setTabBar(TabBar(self))
        self.mainwidget.setTabsClosable(False)
        self.setCentralWidget(self.mainwidget)
        self.dock1 = QDockWidget()
        self.dock2 = QDockWidget()
        self.dock3 = QDockWidget()
        self.dock4 = QDockWidget()
        self.dock5 = QDockWidget()
        for a in (self.dock1, self.dock2, self.dock3, self.dock4, self.dock5):
            a.setWindowModality(Qt.NonModal)
            # a.setWindowOpacity(0.9)
            a.setWindowTitle(__doc__
                             if a.windowTitle() == '' else a.windowTitle())
            a.setStyleSheet('QDockWidget::title{text-align:center;}')
            self.mainwidget.addTab(a, QIcon.fromTheme("face-smile"),
                                   'Double Click Me')

        # Paleta de colores para pintar transparente
        self.palette().setBrush(QPalette.Base, Qt.transparent)
        self.setPalette(self.palette())
        self.setAttribute(Qt.WA_OpaquePaintEvent, False)

        # toolbar and basic actions
        self.toolbar = QToolBar(self)
        self.toolbar.setIconSize(QSize(24, 24))
        # spacer widget for left
        self.left_spacer = QWidget(self)
        self.left_spacer.setSizePolicy(QSizePolicy.Expanding,
                                       QSizePolicy.Expanding)
        # spacer widget for right
        self.right_spacer = QWidget(self)
        self.right_spacer.setSizePolicy(QSizePolicy.Expanding,
                                        QSizePolicy.Expanding)
        qaqq = QAction(QIcon.fromTheme("application-exit"), 'Quit', self)
        qaqq.setShortcut('Ctrl+Q')
        qaqq.triggered.connect(exit)
        qamin = QAction(QIcon.fromTheme("go-down"), 'Minimize', self)
        qamin.triggered.connect(lambda: self.showMinimized())
        qamax = QAction(QIcon.fromTheme("go-up"), 'Maximize', self)
        qanor = QAction(QIcon.fromTheme("view-fullscreen"),
                        'AutoCenter AutoResize', self)
        qanor.triggered.connect(self.center)
        qatim = QAction(QIcon.fromTheme("mail-signed-verified"),
                        'View Date and Time', self)
        qatim.triggered.connect(self.timedate)
        qabug = QAction(QIcon.fromTheme("help-about"), 'Report a Problem', self)
        qabug.triggered.connect(lambda: qabug.setDisabled(True) if not call(
            'xdg-open mailto:' + '*****@*****.**'.decode('rot13'),
            shell=True) else ' ERROR ')
        qamax.triggered.connect(lambda: self.showMaximized())
        qaqt = QAction(QIcon.fromTheme("help-about"), 'About Qt', self)
        qaqt.triggered.connect(lambda: QMessageBox.aboutQt(self))
        qakde = QAction(QIcon.fromTheme("help-about"), 'About KDE', self)
        if KDE:
            qakde.triggered.connect(KHelpMenu(self, "", False).aboutKDE)
        qaslf = QAction(QIcon.fromTheme("help-about"), 'About Self', self)
        if KDE:
            qaslf.triggered.connect(
                                KAboutApplicationDialog(aboutData, self).exec_)
        else:
            qaslf.triggered.connect(lambda: QMessageBox.about(self.mainwidget,
            __doc__, ''.join((__doc__, linesep, 'version ', __version__, ', (',
            __license__, '), by ', __author__, ', ( ', __email__, ' )', linesep
            ))))
        qafnt = QAction(QIcon.fromTheme("tools-check-spelling"),
                        'Set GUI Font', self)
        if KDE:
            font = QFont()
            qafnt.triggered.connect(lambda:
            self.setStyleSheet(''.join((
                '*{font-family:', str(font.toString()), '}'))
                if KFontDialog.getFont(font)[0] == QDialog.Accepted else ''))
        else:
            qafnt.triggered.connect(lambda:
                self.setStyleSheet(''.join(('*{font-family:',
                            str(QFontDialog.getFont()[0].toString()), '}'))))
        qasrc = QAction(QIcon.fromTheme("applications-development"),
                        'View Source Code', self)
        qasrc.triggered.connect(lambda:
                            call('xdg-open {}'.format(__file__), shell=True))
        qakb = QAction(QIcon.fromTheme("input-keyboard"),
                       'Keyboard Shortcuts', self)
        qakb.triggered.connect(lambda: QMessageBox.information(self.mainwidget,
                               'Keyboard Shortcuts', ' Ctrl+Q = Quit '))
        qapic = QAction(QIcon.fromTheme("camera-photo"),
                        'Take a Screenshot', self)
        qapic.triggered.connect(lambda: QPixmap.grabWindow(
            QApplication.desktop().winId()).save(QFileDialog.getSaveFileName(
            self.mainwidget, " Save Screenshot As ...", path.expanduser("~"),
            ';;(*.png) PNG', 'png')))
        qatb = QAction(QIcon.fromTheme("go-top"), 'Toggle ToolBar', self)
        qatb.triggered.connect(lambda: self.toolbar.hide()
                if self.toolbar.isVisible() is True else self.toolbar.show())
        qati = QAction(QIcon.fromTheme("zoom-in"),
                       'Switch ToolBar Icon Size', self)
        qati.triggered.connect(lambda:
            self.toolbar.setIconSize(self.toolbar.iconSize() * 4)
            if self.toolbar.iconSize().width() * 4 == 24
            else self.toolbar.setIconSize(self.toolbar.iconSize() / 4))
        qasb = QAction(QIcon.fromTheme("preferences-other"),
                       'Toggle Tabs Bar', self)
        qasb.triggered.connect(lambda: self.mainwidget.tabBar().hide()
                               if self.mainwidget.tabBar().isVisible() is True
                               else self.mainwidget.tabBar().show())
        qadoc = QAction(QIcon.fromTheme("help-browser"), 'On-line Docs', self)
        qadoc.triggered.connect(lambda: open_new_tab(str(__url__).strip()))
        qapy = QAction(QIcon.fromTheme("help-about"), 'About Python', self)
        qapy.triggered.connect(lambda: open_new_tab('http://python.org/about'))
        qali = QAction(QIcon.fromTheme("help-browser"), 'Read Licence', self)
        qali.triggered.connect(lambda: open_new_tab(__full_licence__))
        qacol = QAction(QIcon.fromTheme("preferences-system"), 'Set GUI Colors',
                        self)
        if KDE:
            color = QColor()
            qacol.triggered.connect(lambda:
                self.setStyleSheet(''.join(('* { background-color: ',
                                            str(color.name()), '}')))
                if KColorDialog.getColor(color, self) else '')
        else:
            qacol.triggered.connect(lambda: self.setStyleSheet(''.join((
                ' * { background-color: ', str(QColorDialog.getColor().name()),
                ' } '))))
        qatit = QAction(QIcon.fromTheme("preferences-system"),
                        'Set the App Window Title', self)
        qatit.triggered.connect(self.seTitle)
        self.toolbar.addWidget(self.left_spacer)
        self.toolbar.addSeparator()
        self.toolbar.addActions((qaqq, qamin, qanor, qamax, qasrc, qakb, qacol,
            qatim, qatb, qafnt, qati, qasb, qatit, qapic, qadoc, qali, qaslf,
            qaqt, qakde, qapy, qabug))
        self.addToolBar(Qt.TopToolBarArea, self.toolbar)
        self.toolbar.addSeparator()
        self.toolbar.addWidget(self.right_spacer)
        # define the menu
        menu = self.menuBar()
        # File menu items
        menu.addMenu('&File').addActions((qaqq, ))
        menu.addMenu('&Window').addActions((qamax, qanor, qamin))
        # Settings menu
        menu.addMenu('&Settings').addActions((qasrc, qacol, qafnt, qatim,
                                              qatb, qati, qasb, qapic))
        # Help menu items
        menu.addMenu('&Help').addActions((qadoc, qakb, qabug, qali,
                                          qaqt, qakde, qapy, qaslf))
        # Tray Icon
        tray = QSystemTrayIcon(QIcon.fromTheme("face-devilish"), self)
        tray.setToolTip(__doc__)
        traymenu = QMenu()
        traymenu.addActions((qamax, qanor, qamin, qaqq))
        tray.setContextMenu(traymenu)
        tray.show()

        def contextMenuRequested(point):
            ' quick and dirty custom context menu '
            menu = QMenu()
            menu.addActions((qaqq, qamin, qanor, qamax, qasrc, qakb, qacol,
                qafnt, qati, qasb, qatb, qatim, qatit, qapic, qadoc, qali,
                qaslf, qaqt, qakde, qapy, qabug))
            menu.exec_(self.mapToGlobal(point))
        self.mainwidget.customContextMenuRequested.connect(contextMenuRequested)

        def must_be_checked(widget_list):
            ' widget tuple passed as argument should be checked as ON '
            for each_widget in widget_list:
                try:
                    each_widget.setChecked(True)
                except:
                    pass

        def must_have_tooltip(widget_list):
            ' widget tuple passed as argument should have tooltips '
            for each_widget in widget_list:
                try:
                    each_widget.setToolTip(each_widget.text())
                except:
                    each_widget.setToolTip(each_widget.currentText())
                finally:
                    each_widget.setCursor(QCursor(Qt.PointingHandCursor))

        def must_autofillbackground(widget_list):
            ' widget tuple passed as argument should have filled background '
            for each_widget in widget_list:
                try:
                    each_widget.setAutoFillBackground(True)
                except:
                    pass

        def must_glow(widget_list):
            ' apply an glow effect to the widget '
            for glow, each_widget in enumerate(widget_list):
                try:
                    if each_widget.graphicsEffect() is None:
                        glow = QGraphicsDropShadowEffect(self)
                        glow.setOffset(0)
                        glow.setBlurRadius(99)
                        glow.setColor(QColor(99, 255, 255))
                        each_widget.setGraphicsEffect(glow)
                        # glow.setEnabled(False)
                        try:
                            each_widget.clicked.connect(lambda:
                            each_widget.graphicsEffect().setEnabled(True)
                            if each_widget.graphicsEffect().isEnabled() is False
                            else each_widget.graphicsEffect().setEnabled(False))
                        except:
                            each_widget.sliderPressed.connect(lambda:
                            each_widget.graphicsEffect().setEnabled(True)
                            if each_widget.graphicsEffect().isEnabled() is False
                            else each_widget.graphicsEffect().setEnabled(False))
                except:
                    pass

        #######################################################################

        # dock 1
        QLabel('<h1 style="color:white;"> Record !</h1>', self.dock1).resize(
               self.dock3.size().width() / 4, 25)
        self.group1 = QGroupBox()
        self.group1.setTitle(__doc__)

        self.spec = QPushButton(self)
        self.spec.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.spec.setMinimumSize(self.spec.size().width(), 250)
        self.spec.setFlat(True)
        self.spec.clicked.connect(self.spectro)

        self.clock = QLCDNumber()
        self.clock.setSegmentStyle(QLCDNumber.Flat)
        self.clock.setMinimumSize(self.clock.size().width(), 50)
        self.clock.setNumDigits(25)
        self.timer1 = QTimer(self)
        self.timer1.timeout.connect(lambda: self.clock.display(
            datetime.now().strftime("%d-%m-%Y %H:%M:%S %p")))
        self.timer1.start(1000)
        self.clock.setToolTip(datetime.now().strftime("%c %x"))
        self.clock.setCursor(QCursor(Qt.CrossCursor))

        self.diskBar = QProgressBar()
        self.diskBar.setMinimum(0)
        self.diskBar.setMaximum(statvfs(HOME).f_blocks *
            statvfs(HOME).f_frsize / 1024 / 1024 / 1024)
        self.diskBar.setValue(statvfs(HOME).f_bfree *
            statvfs(HOME).f_frsize / 1024 / 1024 / 1024)
        self.diskBar.setToolTip(str(statvfs(HOME).f_bfree *
            statvfs(HOME).f_frsize / 1024 / 1024 / 1024) + ' Gigabytes free')

        self.feedback = QPlainTextEdit(''.join(('<center><h3>', __doc__,
            ', version', __version__, __license__, ' <br> by ', __author__,
            ' <i>(Dev)</i>, Radio Comunitaria FM Reconquista <i>(Q.A.)</i><br>',
            'FMReconquista.org.ar & GitHub.com/JuanCarlosPaco/Cinta-Testigo')))

        self.rec = QPushButton(QIcon.fromTheme("media-record"), 'Record')
        self.rec.setMinimumSize(self.rec.size().width(), 50)
        self.rec.clicked.connect(self.go)  # self.run

        self.stop = QPushButton(QIcon.fromTheme("media-playback-stop"), 'Stop')
        self.stop.clicked.connect(self.end)

        self.kill = QPushButton(QIcon.fromTheme("process-stop"), 'Kill')
        self.kill.clicked.connect(self.killer)

        vboxg1 = QVBoxLayout(self.group1)
        for each_widget in (
            QLabel('<b style="color:white;"> Spectro'), self.spec,
            QLabel('<b style="color:white;"> Time '), self.clock,
            QLabel('<b style="color:white;"> Disk '), self.diskBar,
            QLabel('<b style="color:white;"> STDOUT + STDIN '), self.feedback,
            QLabel('<b style="color:white;"> Record '), self.rec, self.stop,
            self.kill):
            vboxg1.addWidget(each_widget)

        self.group2 = QGroupBox()
        self.group2.setTitle(__doc__)

        self.slider = QSlider(self)
        self.slid_l = QLabel(self.slider)
        self.slider.setCursor(QCursor(Qt.OpenHandCursor))
        self.slider.sliderPressed.connect(lambda:
                            self.slider.setCursor(QCursor(Qt.ClosedHandCursor)))
        self.slider.sliderReleased.connect(lambda:
                            self.slider.setCursor(QCursor(Qt.OpenHandCursor)))
        self.slider.valueChanged.connect(lambda:
                            self.slider.setToolTip(str(self.slider.value())))
        self.slider.valueChanged.connect(lambda: self.slid_l.setText(
                    '<h2 style="color:white;">{}'.format(self.slider.value())))
        self.slider.setMinimum(10)
        self.slider.setMaximum(99)
        self.slider.setValue(30)
        self.slider.setOrientation(Qt.Vertical)
        self.slider.setTickPosition(QSlider.TicksBothSides)
        self.slider.setTickInterval(2)
        self.slider.setSingleStep(10)
        self.slider.setPageStep(10)

        vboxg2 = QVBoxLayout(self.group2)
        for each_widget in (
            QLabel('<b style="color:white;">MINUTES of recording'), self.slider,
            QLabel('<b style="color:white;"> Default: 30 Min')):
            vboxg2.addWidget(each_widget)

        group3 = QGroupBox()
        group3.setTitle(__doc__)
        try:
            self.label2 = QLabel(getoutput('sox --version', shell=True))
            self.label4 = QLabel(getoutput('arecord --version', shell=1)[:25])
            self.label6 = QLabel(str(getoutput('oggenc --version', shell=True)))
        except:
            print(''' ERROR: No SOX, OGGenc avaliable !
                  ( sudo apt-get install vorbis-tools sox alsa-utils ) ''')
            exit()

        self.button5 = QPushButton(QIcon.fromTheme("audio-x-generic"),
                                   'OGG --> ZIP')
        self.button5.clicked.connect(lambda: make_archive(
            str(QFileDialog.getSaveFileName(self, "Save OGG to ZIP file As...",
            getcwd(), ';;(*.zip)', 'zip')).replace('.zip', ''), "zip",
            path.abspath(path.join(getcwd(), str(datetime.now().year)))))

        self.button1 = QPushButton(QIcon.fromTheme("folder-open"), 'Files')
        self.button1.clicked.connect(lambda:
                                     call('xdg-open ' + getcwd(), shell=True))

        self.button0 = QPushButton(
            QIcon.fromTheme("preferences-desktop-screensaver"), 'LCD OFF')
        self.button0.clicked.connect(lambda:
            call('sleep 3 ; xset dpms force off', shell=True))

        vboxg3 = QVBoxLayout(group3)
        for each_widget in (
            QLabel('<b style="color:white;"> OGG Output Codec '), self.label6,
            QLabel('<b style="color:white;"> Raw Record Backend '), self.label4,
            QLabel('<b style="color:white;"> Helper Libs '), self.label2,
            QLabel('<b style="color:white;"> OGG ZIP '), self.button5,
            QLabel('<b style="color:white;"> Files '), self.button1,
            QLabel('<b style="color:white;"> LCD '), self.button0):
            vboxg3.addWidget(each_widget)
        container = QWidget()
        hbox = QHBoxLayout(container)
        for each_widget in (self.group2, self.group1, group3):
            hbox.addWidget(each_widget)
        self.dock1.setWidget(container)

        # dock 2
        QLabel('<h1 style="color:white;"> Hardware !</h1>', self.dock2).resize(
               self.dock2.size().width() / 4, 25)
        try:
            audioDriverStr = {Solid.AudioInterface.Alsa: "ALSA",
                Solid.AudioInterface.OpenSoundSystem: "Open Sound",
                Solid.AudioInterface.UnknownAudioDriver: "Unknown?"}
            audioInterfaceTypeStr = {
                Solid.AudioInterface.AudioControl: "Control",
                Solid.AudioInterface.UnknownAudioInterfaceType: "Unknown?",
                Solid.AudioInterface.AudioInput: "In",
                Solid.AudioInterface.AudioOutput: "Out"}
            soundcardTypeStr = {
                Solid.AudioInterface.InternalSoundcard: "Internal",
                Solid.AudioInterface.UsbSoundcard: "USB3",
                Solid.AudioInterface.FirewireSoundcard: "FireWire",
                Solid.AudioInterface.Headset: "Headsets",
                Solid.AudioInterface.Modem: "Modem"}
            display = QTreeWidget()
            display.setAlternatingRowColors(True)
            display.setHeaderLabels(["Items", "ID", "Drivers", "I / O", "Type"])
            display.setColumnWidth(0, 350)
            display.setColumnWidth(1, 350)
            display.setColumnWidth(3, 75)
            # retrieve a list of Solid.Device for this machine
            deviceList = Solid.Device.allDevices()
            # filter the list of all devices and display matching results
            # note that we never create a Solid.AudioInterface object, but
            # receive one from the 'asDeviceInterface' call
            for device in deviceList:
                if device.isDeviceInterface(
                                         Solid.DeviceInterface.AudioInterface):
                    audio = device.asDeviceInterface(
                            Solid.DeviceInterface.AudioInterface)
                    devtype = audio.deviceType()
                    devstr = []
                    for key in audioInterfaceTypeStr:
                        flag = key & devtype
                        if flag:
                            devstr.append(audioInterfaceTypeStr[key])
                    QTreeWidgetItem(display, [device.product(), audio.name(),
                        audioDriverStr[audio.driver()], "/".join(devstr),
                        soundcardTypeStr[audio.soundcardType()]])
            self.dock2.setWidget(display)
        except:
            self.dock2.setWidget(QLabel(""" <center style='color:white;'>
            <h1>:(<br>ERROR: Please, install PyKDE !</h1><br>
            <br><i> (Sorry, can not use non-Qt Libs). Thanks </i><center>"""))

        ## dock 3
        QLabel('<h1 style="color:white;"> Previews !</h1>', self.dock3).resize(
               self.dock3.size().width() / 4, 25)
        self.fileView = QColumnView()
        self.fileView.updatePreviewWidget.connect(self.play)
        self.fileView.setToolTip(' Browse and Preview Files ')
        self.media = None
        self.model = QDirModel()
        self.fileView.setModel(self.model)
        self.dock3.setWidget(self.fileView)

        # dock4
        QLabel('<h1 style="color:white;"> Setup !</h1>', self.dock4).resize(
               self.dock4.size().width() / 4, 25)
        self.group4 = QGroupBox()
        self.group4.setTitle(__doc__)

        self.combo0 = QComboBox()
        self.combo0.addItems(['S16_LE', 'S32_LE', 'S16_BE', 'U16_LE', 'U16_BE',
          'S24_LE', 'S24_BE', 'U24_LE', 'U24_BE', 'S32_BE', 'U32_LE', 'U32_BE'])

        self.combo1 = QComboBox()
        self.combo1.addItems(['1', '-1', '0', '2', '3', '4',
                              '5', '6', '7', '8', '9', '10'])

        self.combo2 = QComboBox()
        self.combo2.addItems(['128', '256', '512', '1024', '64', '32', '16'])

        self.combo3 = QComboBox(self)
        self.combo3.addItems(['MONO', 'STEREO', 'Surround'])

        self.combo4 = QComboBox()
        self.combo4.addItems(['44100', '96000', '48000', '32000',
                              '22050', '16000', '11025', '8000'])

        self.combo5 = QComboBox(self)
        self.combo5.addItems(['20', '19', '18', '17', '16', '15', '14', '13',
            '12', '10', '9', '8', '7', '6', '5', '4', '3', '2', '1', '0'])

        self.nepochoose = QCheckBox('Auto-Tag Files using Nepomuk Semantic')

        self.chckbx0 = QCheckBox('Disable Software based Volume Control')

        self.chckbx1 = QCheckBox('Output Sound Stereo-to-Mono Downmix')

        self.chckbx2 = QCheckBox('Add Date and Time MetaData to Sound files')

        self.chckbx3 = QCheckBox('Add Yourself as the Author Artist of Sound')

        vboxg4 = QVBoxLayout(self.group4)
        for each_widget in (
            QLabel('<b style="color:white;"> Sound OGG Quality'), self.combo1,
            QLabel('<b style="color:white;"> Sound Record Format'), self.combo0,
            QLabel('<b style="color:white;"> Sound KBps '), self.combo2,
            QLabel('<b style="color:white;"> Sound Channels '), self.combo3,
            QLabel('<b style="color:white;"> Sound Sample Rate '), self.combo4,
            QLabel('<b style="color:white;"> Sound Volume'), self.chckbx0,
            QLabel('<b style="color:white;"> Sound Mix'), self.chckbx1,
            QLabel('<b style="color:white;"> Sound Meta'), self.chckbx2,
            QLabel('<b style="color:white;"> Sound Authorship'), self.chckbx3,
            QLabel('<b style="color:white;"> CPUs Priority'), self.combo5,
            QLabel('<b style="color:white;">Nepomuk Semantic User Experience'),
            self.nepochoose):
            vboxg4.addWidget(each_widget)
        self.dock4.setWidget(self.group4)

        # dock 5
        QLabel('<h1 style="color:white;"> Voice Changer ! </h1>', self.dock5
               ).resize(self.dock5.size().width() / 3, 25)
        self.group5 = QGroupBox()
        self.group5.setTitle(__doc__)

        self.dial = QDial()
        self.dial.setCursor(QCursor(Qt.OpenHandCursor))
        self.di_l = QLabel(self.dial)
        self.di_l.resize(self.dial.size() / 8)
        self.dial.sliderPressed.connect(lambda:
                            self.dial.setCursor(QCursor(Qt.ClosedHandCursor)))
        self.dial.sliderReleased.connect(lambda:
                            self.dial.setCursor(QCursor(Qt.OpenHandCursor)))
        self.dial.valueChanged.connect(lambda:
                            self.dial.setToolTip(str(self.dial.value())))
        self.dial.valueChanged.connect(lambda: self.di_l.setText(
                    '<h1 style="color:white;">{}'.format(self.dial.value())))
        self.dial.setValue(0)
        self.dial.setMinimum(-999)
        self.dial.setMaximum(999)
        self.dial.setSingleStep(100)
        self.dial.setPageStep(100)
        self.dial.setWrapping(False)
        self.dial.setNotchesVisible(True)

        self.defo = QPushButton(QIcon.fromTheme("media-playback-start"), 'Run')
        self.defo.setMinimumSize(self.defo.size().width(), 50)
        self.defo.clicked.connect(lambda: self.process3.start(
            'play -q -V0 "|rec -q -V0 -n -d -R riaa pitch {} "'
            .format(self.dial.value()) if int(self.dial.value()) != 0 else
            'play -q -V0 "|rec -q -V0 --multi-threaded -n -d -R bend {} "'
            .format(' 3,2500,3 3,-2500,3 ' * 999)))

        self.qq = QPushButton(QIcon.fromTheme("media-playback-stop"), 'Stop')
        self.qq.clicked.connect(self.process3.kill)

        self.die = QPushButton(QIcon.fromTheme("process-stop"), 'Kill')
        self.die.clicked.connect(lambda: call('killall rec', shell=True))

        vboxg5 = QVBoxLayout(self.group5)
        for each_widget in (self.dial, self.defo, self.qq, self.die):
            vboxg5.addWidget(each_widget)
        self.dock5.setWidget(self.group5)

        # configure some widget settings
        must_be_checked((self.nepochoose, self.chckbx1,
                         self.chckbx2, self.chckbx3))
        must_have_tooltip((self.label2, self.label4, self.label6, self.combo0,
            self.nepochoose, self.combo1, self.combo2, self.combo3, self.combo4,
            self.combo5, self.chckbx0, self.chckbx1, self.chckbx2, self.chckbx3,
            self.rec, self.stop, self.defo, self.qq, self.die, self.kill,
            self.button0, self.button1, self.button5))
        must_autofillbackground((self.clock, self.label2, self.label4,
            self.label6, self.nepochoose, self.chckbx0, self.chckbx1,
            self.chckbx2, self.chckbx3))
        must_glow((self.rec, self.dial, self.combo1))
        self.nepomuk_get('testigo')
        if self.auto is True:
            self.go()
示例#11
0
class Tray(QObject):
    activated = pyqtSignal()

    def __init__(self, parent, title, icon):
        QObject.__init__(self)

        # Setup contextual menu
        if kde:
            self.menu = KMenu(parent)
            self.tray = KStatusNotifierItem(parent)
            self.tray.setStatus(KStatusNotifierItem.Passive)
            self.tray.setCategory(KStatusNotifierItem.ApplicationStatus)
            self.tray.setAssociatedWidget(parent)
            self.tray.setStandardActionsEnabled(False)
            self.tray.activateRequested.connect(self._activateRequested)
        else:
            self.menu = QMenu()
            self.tray = QSystemTrayIcon()
            self.tray.activated.connect(self._activated)
        self.setIcon(icon)
        self.setTitle(title)
        if not kde:
            self.tray.show()
        self.tray.setContextMenu(self.menu)

    def setActive(self, active=True):
        if kde:
            self.tray.setStatus(KStatusNotifierItem.Active
                                if active else KStatusNotifierItem.Passive)

    def setTitle(self, title):
        if kde:
            self.tray.setTitle(title)
            self.tray.setToolTipTitle(title)
        else:
            self.tray.setToolTip(title)
        self.menu.setTitle(title)

    def setToolTipSubTitle(self, subtitle):
        if kde:
            self.tray.setToolTipSubTitle(subtitle)

    def setIcon(self, icon):
        if kde:
            self.tray.setIconByPixmap(icon)
            self.tray.setToolTipIconByPixmap(icon)
        else:
            self.tray.setIcon(icon)

    def showMessage(self, title, message, icon=None):
        if kde:
            self.tray.showMessage(title, message, "network-server")
        else:
            self.tray.showMessage(
                title, message,
                QSystemTrayIcon.Information if icon is None else icon)

    def _activated(self, reason):
        if reason == QSystemTrayIcon.DoubleClick:
            self.activated.emit()

    def _activateRequested(self, active, pos):
        self.activated.emit()
示例#12
0
class Platform(QObject):
    def __init__(self):
        QObject.__init__(self)
        documentsLocation = QDesktopServices.storageLocation(
            QDesktopServices.DocumentsLocation)
        self.databaseFile = os.path.join(documentsLocation, "quickpanel.db")
        self._settings = _Settings(self.databaseFile)
        self.globalKey = GlobalKey()
        self.quickPanel = QuickPanel(self)
        self.actionConfigure = QAction(QIcon(":/images/configure.png"), \
                self.trUtf8("&Configure"), self)
        self.actionExit = QAction(QIcon(":/images/close.png"), \
                self.trUtf8("&Exit"), self)
        self.trayIcon = QSystemTrayIcon(QIcon(":/images/angelfish.png"))
        self.contextMenu = QMenu()
        self.contextMenu.addAction(self.actionConfigure)
        self.contextMenu.addAction(self.actionExit)
        self.trayIcon.setContextMenu(self.contextMenu)
        self.actionConfigure.triggered.connect(self.configure)
        self.actionExit.triggered.connect(self.exit)
        self.trayIcon.activated.connect(self.onTrayIconActivated)

    def start(self):
        self.loadSettings()
        self.trayIcon.show()
        self.quickPanel.initWidgets()
        logger.info("QuickPanel is launched.")
        self.quickPanel.addQuickAccessShortcut(self.trUtf8("Tetrix"), \
                QIcon(":/images/tetrix.png"), self.startTetrix)
        self.quickPanel.addQuickAccessShortcut(self.trUtf8("Hello"), \
                QIcon(":/images/hello.png"), self.sayHello)

    def startTetrix(self):
        if getattr(self, "tetrixWindow", None) is None:
            self.tetrixWindow = TetrixWindow()
        self.tetrixWindow.show()
        self.tetrixWindow.activateWindow()

    def sayHello(self):
        QMessageBox.information(None, self.trUtf8("Say Hello."), \
                self.trUtf8("Hello, world!"))

    def loadSettings(self):
        settings = self.getSettings()
        keyname = settings.value("globalkey", "Alt+`")
        self.keyId = self.globalKey.addHotKey("actionToggleQuickPanel",
                                              keyname)
        self.globalKey.catched.connect(self.quickPanel.toggle)

    def saveSettings(self):
        pass

    def configure(self):
        d = ConfigureDialog()
        settings = self.getSettings()
        keyname = settings.value("globalkey", "Alt+`")
        d.setGlobalKey(keyname)
        self.globalKey.removeHotKey(self.keyId)
        try:
            result = getattr(d, "exec")()
        except AttributeError:
            result = getattr(d, "exec_")()
        if result == QDialog.Accepted:
            keyname = d.getGlobalKey()
            settings.setValue("globalkey", keyname)
        self.keyId = self.globalKey.addHotKey("actionToggleQuickPanel",
                                              keyname)

    def exit(self):
        self.quickPanel.finalize()
        self.saveSettings()
        self.globalKey.close()
        logger.info("QuickPanel is shutting down.")
        QApplication.instance().quit()

    def onTrayIconActivated(self, reason):
        if reason == QSystemTrayIcon.Trigger:
            self.quickPanel.toggle()

    def getSettings(self):
        return Settings(self._settings)
示例#13
0
class MainWindow(QMainWindow):
    groups = dict()
    typeQListWidgetHeader = 1000
    showHostsInGroups = False
    currentGroupName = None  # used to simple detect currently selected group to show menu

    def __init__(self):
        super(MainWindow, self).__init__()
        self.config = Config()
        self.db = Database(self.config.getConnectionString())

        cryptoKey = self.getCryptoKey()
        self.hosts = Hosts(self.db, cryptoKey)

        # menu used for each host
        self.hostMenu = QMenu()
        self.editAction = QAction(QIcon(':/ico/edit.svg'), "Edit", self.hostMenu)
        self.editAction.triggered.connect(self.editHost)
        self.hostMenu.addAction(self.editAction)

        # menu used for headers of groups
        self.groupsHeaderMenu = QMenu()
        self.editGroupAction = QAction(QIcon(':/ico/edit.svg'), "Edit group", self.groupsHeaderMenu)
        self.editGroupAction.triggered.connect(self.editGroup)
        self.deleteGroupAction = QAction(QIcon(':/ico/remove.svg'), "Delete group", self.groupsHeaderMenu)
        self.deleteGroupAction.triggered.connect(self.deleteGroup)
        self.groupsHeaderMenu.addAction(self.editGroupAction)
        self.groupsHeaderMenu.addAction(self.deleteGroupAction)

        self.duplicateAction = QAction(QIcon(':/ico/copy.svg'), "Duplicate", self.hostMenu)
        self.duplicateAction.triggered.connect(self.duplicateHost)
        self.hostMenu.addAction(self.duplicateAction)

        # todo: confirm for delete action
        self.deleteAction = QAction(QIcon(':/ico/remove.svg'), "Delete", self.hostMenu)
        self.deleteAction.triggered.connect(self.deleteHost)
        self.hostMenu.addAction(self.deleteAction)

        self.connectFramelessMenu = actions.generateScreenChoseMenu(self.hostMenu, self.connectFrameless,
                                                                    ':/ico/frameless.svg', "Connect frameless")
        self.hostMenu.addMenu(self.connectFramelessMenu)

        self.assignGroupAction = QAction("Assign group", self.hostMenu)
        self.assignGroupAction.triggered.connect(self.assignGroup)
        self.hostMenu.addAction(self.assignGroupAction)

        # setup main window
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

        # when top level changed, we changing dock title bar
        self.dockWidgetTileBar = DockWidgetTitleBar()
        self.ui.hostsDock.setTitleBarWidget(self.dockWidgetTileBar)
        self.ui.hostsDock.topLevelChanged.connect(self.dockLevelChanged)

        # set global menu
        self.globalMenu = QMenu()
        self.globalMenu.addAction(QIcon(':/ico/add.svg'), 'Add host', self.addHost)

        # groups menu
        self.groupsMenu = QMenu("Groups")
        self.groupsMenu.aboutToShow.connect(self.setGroupsMenu)
        self.globalMenu.addMenu(self.groupsMenu)

        # disable menu indicator
        self.ui.menu.setStyleSheet("QPushButton::menu-indicator {image: none;}")
        self.positionMenu = QMenu("Dock position")
        self.positionMenu.addAction("Left", lambda: self.setDockPosition(Qt.LeftDockWidgetArea))
        self.positionMenu.addAction("Right", lambda: self.setDockPosition(Qt.RightDockWidgetArea))
        self.positionMenu.addAction("Float", self.setDockFloat)
        self.globalMenu.addMenu(self.positionMenu)
        self.globalMenu.addAction('Change tray icon visibility', self.changeTrayIconVisibility)
        self.globalMenu.addAction('Settings', self.showSettings)
        self.globalMenu.addAction('Quit', self.close)
        self.ui.menu.setMenu(self.globalMenu)

        # set events on hosts list
        self.ui.hostsList.itemDoubleClicked.connect(self.slotConnectHost)
        self.ui.hostsList.itemClicked.connect(self.slotShowHost)
        self.ui.hostsList.customContextMenuRequested.connect(self.slotShowHostContextMenu)

        # set tab widget
        self.tabWidget = MyTabWidget()
        self.setCentralWidget(self.tabWidget)
        self.tabWidget.setContextMenuPolicy(Qt.CustomContextMenu)
        self.tabWidget.customContextMenuRequested.connect(self.showCentralWidgetContextMenu)

        # set tray icon
        self.tray = QSystemTrayIcon(QIcon(":/ico/myrdp.svg"))
        self.tray.activated.connect(self.trayActivated)

        self.trayMenu = QMenu()
        self.trayMenu.addAction("Hide tray icon", self.changeTrayIconVisibility)
        self.connectHostMenuTray = ConnectHostMenu(self.hosts)
        self.connectHostMenuTray.triggered.connect(self.connectHostFromTrayMenu)
        self.trayMenu.addMenu(self.connectHostMenuTray)
        self.trayMenu.addAction("Quit", self.close)

        self.tray.setContextMenu(self.trayMenu)
        self.restoreSettings()
        # host list
        self.ui.filter.textChanged.connect(self.setHostList)
        self.setHostList()

    def getCryptoKey(self, passphrase=None):
        try:
            return self.config.getPrivateKey(passphrase)
        except ValueError:
            passwordDialog = PasswordDialog()
            retCode = passwordDialog.exec_()
            if retCode == QtGui.QDialog.Accepted:
                return self.getCryptoKey(passwordDialog.getPassword())
            else:
                raise SystemError("Password required")

    def showSettings(self):
        settingsWidget = self.findChild(QWidget, "settings")
        if settingsWidget is None:
            self.settingsWidget = SettingsPage()
            self.settingsWidget.setObjectName("settings")
            self.tabWidget.insertTab(0, self.settingsWidget, QIcon(":/ico/settings.svg"), 'Settings')

        index = self.tabWidget.indexOf(self.settingsWidget)
        self.tabWidget.setCurrentIndex(index)

    def connectHostFromMenu(self, action):
        self.connectHost(unicode(action.text()))

    def connectHostFromTrayMenu(self, action):
        tabPage = self.connectHost(unicode(action.text()))
        if not self.isVisible():
            self.tabWidget.setDetached(True, tabPage)

    def trayActivated(self, reason):
        if reason != QSystemTrayIcon.Trigger:
            return
        if self.isVisible():
            self.hide()
        else:
            self.show()
            self.activateWindow()

    def changeTrayIconVisibility(self):
        if self.tray.isVisible():
            self.tray.hide()
            if not self.isVisible():
                self.show()
        else:
            self.tray.show()

    def refreshGroups(self):
        groupList = self.hosts.getGroupsList()
        for group in groupList:
            if group not in self.groups:
                # add new groups as visible
                self.groups[group] = True

        # remove not existing groups
        keysToDelete = set(self.groups.keys()) - set(groupList)
        for key in keysToDelete:
            self.groups.pop(key)

    def assignGroup(self):
        groups = self.hosts.getGroupsList()
        assignGroupDialog = AssignGroupDialog(groups)
        groupToAssign = assignGroupDialog.assign()
        if groupToAssign is not False:  # None could be used to unassign the group
            groupToAssign = None if groupToAssign.isEmpty() else unicode(groupToAssign)
            for hostName in self.getSelectedHosts():
                self.hosts.assignGroup(hostName, groupToAssign)
            self.db.tryCommit()
            self.setHostList()

    def setGroupsMenu(self):
        self.groupsMenu.clear()
        addGroupAction = self.groupsMenu.addAction('Add group')
        addGroupAction.triggered.connect(self.addGroup)

        deleteGroupAction = self.groupsMenu.addAction('Delete group')
        deleteGroupAction.triggered.connect(self.showDeleteGroupDialog)

        showHostsInGroupsAction = self.groupsMenu.addAction('Show host list in groups')
        showHostsInGroupsAction.triggered.connect(self.changeHostListView)
        showHostsInGroupsAction.setCheckable(True)
        showHostsInGroupsAction.setChecked(self.showHostsInGroups)

        self.groupsMenu.addSeparator()
        for group, checked in self.groups.items():
            action = QAction(group, self.groupsMenu)
            action.setCheckable(True)
            action.setChecked(checked)
            action.triggered.connect(self.groupsVisibilityChanged)
            self.groupsMenu.addAction(action)

    def addGroup(self):
        groupConfigDialog = GroupConfigDialog(self.hosts.groups)
        resp = groupConfigDialog.add()
        self._processHostSubmit(resp)

    def groupsVisibilityChanged(self, checked):
        currentGroup = unicode(self.sender().text())
        self.groups[currentGroup] = checked
        self.setHostList()

    def setDockPosition(self, dockWidgetArea):
        if self.ui.hostsDock.isFloating():
            self.ui.hostsDock.setFloating(False)
        self.addDockWidget(dockWidgetArea, self.ui.hostsDock)

    def setDockFloat(self):
        if self.ui.hostsDock.isFloating():
            return
        # default title bar must be set before is float because sometimes window make strange crash
        self.ui.hostsDock.setTitleBarWidget(None)
        self.ui.hostsDock.setFloating(True)

    def dockLevelChanged(self, isFloating):
        if isFloating:
            # changing title bar widget if is not none, probably true will be only once on start with saved float state
            if self.ui.hostsDock.titleBarWidget():
                self.ui.hostsDock.setTitleBarWidget(None)
        else:
            self.ui.hostsDock.setTitleBarWidget(self.dockWidgetTileBar)

    def showFramelessWidget(self):
        self.t.show()
        self.t.setGeometry(self.frameGeometry())

    def getCurrentHostListItemName(self):
        return self.ui.hostsList.currentItem().text()

    def getSelectedHosts(self):
        return [host.text() for host in self.ui.hostsList.selectedItems()]

    def findHostItemByName(self, name):
        result = self.ui.hostsList.findItems(name, Qt.MatchExactly)
        resultLen = len(result)
        if resultLen != 1:  # should be only one host
            logger.error("Host not found. Got %d results" % resultLen)
        return result[0]

    def showCentralWidgetContextMenu(self, pos):
        menu = QMenu()
        title = self.ui.hostsDock.windowTitle()

        hostsDockAction = menu.addAction(title)
        hostsDockAction.setCheckable(True)
        hostsDockAction.setChecked(self.ui.hostsDock.isVisible())
        hostsDockAction.triggered.connect(self.changeHostsDockWidgetVisibility)

        hostsDockAction = menu.addAction("Tray icon")
        hostsDockAction.setCheckable(True)
        hostsDockAction.setChecked(self.tray.isVisible())
        hostsDockAction.triggered.connect(self.changeTrayIconVisibility)

        connectHostMenuTray = ConnectHostMenu(self.hosts, "Connect")
        connectHostMenuTray.triggered.connect(self.connectHostFromMenu)
        menu.addMenu(connectHostMenuTray)

        menu.exec_(self.tabWidget.mapToGlobal(pos))

    def changeHostListView(self, checked):
        self.showHostsInGroups = checked
        self.setHostList()

    def changeHostsDockWidgetVisibility(self):
        isVisible = self.ui.hostsDock.isVisible()
        self.ui.hostsDock.setVisible(not isVisible)

    def isHostListHeader(self, item):
        if not item or item.type() == self.typeQListWidgetHeader:
            return True
        return False

    def slotShowHostContextMenu(self, pos):
        def changeMenusVisibility(isEnabled):
            self.connectFramelessMenu.setEnabled(isEnabled)
            self.editAction.setEnabled(isEnabled)
            self.duplicateAction.setEnabled(isEnabled)

        # ignore context menu for group headers
        item = self.ui.hostsList.itemAt(pos)

        if self.isHostListHeader(item):
            item = self.ui.hostsList.itemAt(pos)
            widgetItem = self.ui.hostsList.itemWidget(item)
            if widgetItem:
                self.currentGroupName = widgetItem.text()  # yea I'm so dirty
                if self.currentGroupName != unassignedGroupName:
                    self.groupsHeaderMenu.exec_(self.ui.hostsList.mapToGlobal(pos))
            return

        if len(self.ui.hostsList.selectedItems()) == 1:  # single menu
            changeMenusVisibility(True)
        else:
            changeMenusVisibility(False)

        self.hostMenu.exec_(self.ui.hostsList.mapToGlobal(pos))

    def _processHostSubmit(self, resp):
        if resp["code"]:
            self.setHostList()
        hostName = resp.get("name")
        if hostName:
            hostItem = self.findHostItemByName(hostName)
            self.slotConnectHost(hostItem)

    def addHost(self):
        hostDialog = HostConfigDialog(self.hosts)
        self._processHostSubmit(hostDialog.add())

    def editHost(self):
        hostDialog = HostConfigDialog(self.hosts)
        resp = hostDialog.edit(self.getCurrentHostListItemName())
        self._processHostSubmit(resp)

    def editGroup(self):
        groupConfigDialog = GroupConfigDialog(self.hosts.groups)
        resp = groupConfigDialog.edit(self.currentGroupName)
        self._processHostSubmit(resp)

    def deleteGroup(self):
        retCode = self.showOkCancelMessageBox("Do you want to remove selected group? All assigned hosts "
                                              "to this group will be unassigned.",
                                              "Confirmation")
        if retCode == QMessageBox.Cancel:
            return

        self.hosts.deleteGroup(self.currentGroupName)
        self.setHostList()

    def showDeleteGroupDialog(self):
        deleteGroupDialog = DeleteGroupDialog(self.hosts)
        deleteGroupDialog.deleteGroup()
        self.setHostList()

    def duplicateHost(self):
        hostDialog = HostConfigDialog(self.hosts)
        resp = hostDialog.duplicate(self.getCurrentHostListItemName())
        self._processHostSubmit(resp)

    def deleteHost(self):
        retCode = self.showOkCancelMessageBox("Do you want to remove selected hosts?",
                                              "Confirmation")
        if retCode == QMessageBox.Cancel:
            return

        for host in self.getSelectedHosts():
            self.hosts.delete(host)
        self.setHostList()

    def connectFrameless(self, screenIndex=None):
        self.connectHost(self.getCurrentHostListItemName(), frameless=True, screenIndex=screenIndex)

    # Fix to release keyboard from QX11EmbedContainer, when we leave widget through wm border
    def leaveEvent(self, event):
        keyG = QWidget.keyboardGrabber()
        if keyG is not None:
            keyG.releaseKeyboard()
        event.accept()  # needed?

    def setHostList(self):
        """ set hosts list in list view """
        self.ui.hostsList.clear()
        self.refreshGroups()
        hostFilter = self.ui.filter.text()
        if self.showHostsInGroups:
            self.showHostListInGroups(hostFilter)
        else:
            self.showHostList(hostFilter)

    def showHostList(self, hostFilter):
        groupFilter = [group for group, visibility in self.groups.items() if visibility]
        hosts = self.hosts.getHostsListByHostNameAndGroup(hostFilter, groupFilter)
        self.ui.hostsList.addItems(hosts)

    def showHostListInGroups(self, hostFilter):
        hosts = self.hosts.getGroupedHostNames(hostFilter)
        for group, hostsList in hosts.items():
            if self.groups.get(group, True):
                if group is None:
                    group = unassignedGroupName
                groupHeader = QtGui.QListWidgetItem(type=self.typeQListWidgetHeader)
                groupLabel = QtGui.QLabel(unicode(group))
                groupLabel.setProperty('class', 'group-title')
                self.ui.hostsList.addItem(groupHeader)
                self.ui.hostsList.setItemWidget(groupHeader, groupLabel)
                self.ui.hostsList.addItems(hostsList)

    def slotShowHost(self, item):
        # on one click we activating tab and showing options
        self.tabWidget.activateTab(item)

    def slotConnectHost(self, item):
        if self.isHostListHeader(item):
            return
        self.connectHost(unicode(item.text()))

    def connectHost(self, hostId, frameless=False, screenIndex=None):
        hostId = unicode(hostId)  # sometimes hostId comes as QString
        tabPage = self.tabWidget.createTab(hostId)
        tabPage.reconnectionNeeded.connect(self.connectHost)

        if frameless:
            self.tabWidget.detachFrameless(tabPage, screenIndex)

        try:
            execCmd, opts = self.getCmd(tabPage, hostId)
        except LookupError:
            logger.error(u"Host {} not found.".format(hostId))
            return

        ProcessManager.start(hostId, tabPage, execCmd, opts)
        return tabPage

    def getCmd(self, tabPage, hostName):
        host = self.hosts.get(hostName)

        # set tabPage widget
        width, height = tabPage.setSizeAndGetCurrent()
        # 1et widget winId to embed rdesktop
        winId = tabPage.x11.winId()

        # set remote desktop client, at this time works only with freerdp
        remoteClientType, remoteClientOptions = self.config.getRdpClient()
        remoteClient = ClientFactory(remoteClientType, **remoteClientOptions)
        remoteClient.setWindowParameters(winId, width, height)
        remoteClient.setUserAndPassword(host.user, host.password)
        remoteClient.setAddress(host.address)
        return remoteClient.getComposedCommand()

    def saveSettings(self):
        self.config.setValue("geometry", self.saveGeometry())
        self.config.setValue("windowState", self.saveState())
        self.config.setValue('trayIconVisibility', self.tray.isVisible())
        self.config.setValue('mainWindowVisibility', self.isVisible())
        self.config.setValue('groups', self.groups)
        self.config.setValue('showHostsInGroups', self.showHostsInGroups)

    def restoreSettings(self):
        try:
            self.restoreGeometry(self.config.getValue("geometry").toByteArray())
            self.restoreState(self.config.getValue("windowState").toByteArray())
        except Exception:
            logger.debug("No settings to restore")

        # restore tray icon state
        trayIconVisibility = self.config.getValue('trayIconVisibility', "true").toBool()
        self.tray.setVisible(trayIconVisibility)

        self.showHostsInGroups = self.config.getValue('showHostsInGroups', 'false').toBool()

        if self.tray.isVisible():
            mainWindowVisibility = self.config.getValue('mainWindowVisibility', "true").toBool()
            self.setVisible(mainWindowVisibility)
        else:  # it tray icon is not visible, always show main window
            self.show()

        self.groups = {unicode(k): v for k, v in self.config.getValue('groups', {}).toPyObject().items()}

    def closeEvent(self, event):
        if not ProcessManager.hasActiveProcess:
            self.saveSettings()
            QCoreApplication.exit()
            return

        ret = self.showOkCancelMessageBox("Are you sure do you want to quit?",
                                          "Exit confirmation")
        if ret == QMessageBox.Cancel:
            event.ignore()
            return

        self.saveSettings()
        ProcessManager.killemall()
        event.accept()
        QCoreApplication.exit()

    def showOkCancelMessageBox(self, messageBoxText, windowTitle):
        msgBox = QMessageBox(self, text=messageBoxText)
        msgBox.setWindowTitle(windowTitle)
        msgBox.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
        msgBox.setIcon(QMessageBox.Question)
        return msgBox.exec_()
示例#14
0
class TrayController():
    """Display and control context menu."""

    setings_win = None

    def __init__(self):
        """Create TrayController."""
        self._tray_ico = QSystemTrayIcon()

    def set_menu(self, quit_callable, app_icon):
        """Show tray icon and sets its context menu items.

        :param quit_callable: function to call when user choose Exit menu item
        :type quit_callable: function
        :param app_icon: QIcon object - tray icon image
        :type app_icon: QIcon
        """
        tray_menu = QMenu()

        self._delay_menu = tray_menu.addAction(
            QIcon(
                os.path.join(PROGRAMM_RESOURCE_PATH, 'k-timer-icon.png')
            ),
            QtCore.QCoreApplication.translate('TrayController', 'Delay')
        )
        delay_sub_menu = QMenu()
        delay_sub_menu.addAction(
            QtCore.QCoreApplication.translate('TrayController', '15 minutes'),
            self.action_delay15
        )
        delay_sub_menu.addAction(
            QtCore.QCoreApplication.translate('TrayController', '30 minutes'),
            self.action_delay30
        )
        delay_sub_menu.addAction(
            QtCore.QCoreApplication.translate('TrayController', '1 hour'),
            self.action_delay60
        )
        delay_sub_menu.addAction(
            QtCore.QCoreApplication.translate('TrayController', '2 hours'),
            self.action_delay120
        )
        self._delay_menu.setMenu(delay_sub_menu)

        self._resume_menu = tray_menu.addAction(
            QIcon(
                os.path.join(PROGRAMM_RESOURCE_PATH,
                             'App-Quick-restart-icon.png')
            ),
            QtCore.QCoreApplication.translate('TrayController', 'Resume'),
            self.action_resume
        )
        self._resume_menu.setVisible(False)

        tray_menu.addAction(
            QIcon(
                os.path.join(PROGRAMM_RESOURCE_PATH, 'Settings-icon.png')
            ),
            QtCore.QCoreApplication.translate('TrayController', 'Settings'),
            self.show_settings
        )
        tray_menu.addSeparator()
        tray_menu.addAction(
            QIcon(
                os.path.join(PROGRAMM_RESOURCE_PATH, 'delete-icon.png')
            ),
            QtCore.QCoreApplication.translate('TrayController', 'Exit'),
            quit_callable
        )

        self._tray_ico.setContextMenu(tray_menu)
        self._tray_ico.setToolTip(PROGRAM_NAME)
        self._tray_ico.setIcon(app_icon)
        self._tray_ico.show()
        self.setings_win = SettingsManager(self, app_icon)

    def show_message(self, message):
        """Show message near tray icon.

        (alternative to show message is via module
        from PyQt4.QtGui import QMessageBox)

        :param message: message string
        :type message: str
        """
        self._tray_ico.showMessage(
            PROGRAM_NAME, message,
            msecs=5000
        )

    # Functions - menu click actions
    def toggle_delay_menu(self):
        """Toggle some context menu items.

        (depending program delay is on or off)
        """
        delay_on = self.setings_win.main_timer.delay_on
        self._resume_menu.setVisible(delay_on)
        self._delay_menu.setVisible(not delay_on)
        self.setings_win.ui.notActiveLb.setText(
            QtCore.QCoreApplication.translate('TrayController', 'Delay time')
            if delay_on else
            QtCore.QCoreApplication.translate(
                'TrayController', 'Time not active'
            )
        )

    def action_delay15(self):
        """User choose to delay program on 15 minutes."""
        self.setings_win.main_timer.set_work_delay(15)

    def action_delay30(self):
        """User choose to delay program on 30 minutes."""
        self.setings_win.main_timer.set_work_delay(30)

    def action_delay60(self):
        """User choose to delay program on 1 hour."""
        self.setings_win.main_timer.set_work_delay(60)

    def action_delay120(self):
        """User choose to delay program on 2 hours."""
        self.setings_win.main_timer.set_work_delay(120)

    def action_resume(self):
        """User cancel delay."""
        self.setings_win.main_timer.delay_on = False
        self.toggle_delay_menu()

    def show_settings(self):
        """Show settings window."""
        self.setings_win.show()
示例#15
0
class Qt4SysTrayIcon:
    def __init__( self ):
        self.snapshots = snapshots.Snapshots()
        self.config = self.snapshots.config
        self.decode = None

        if len( sys.argv ) > 1:
            if not self.config.set_current_profile(sys.argv[1]):
                logger.warning("Failed to change Profile_ID %s"
                               %sys.argv[1], self)

        self.qapp = qt4tools.create_qapplication(self.config.APP_NAME)
        translator = qt4tools.get_translator()
        self.qapp.installTranslator(translator)
        self.qapp.setQuitOnLastWindowClosed(False)

        import icon
        self.icon = icon
        self.qapp.setWindowIcon(icon.BIT_LOGO)

        self.status_icon = QSystemTrayIcon(icon.BIT_LOGO)
        #self.status_icon.actionCollection().clear()
        self.contextMenu = QMenu()

        self.menuProfileName = self.contextMenu.addAction(_('Profile: "%s"') % self.config.get_profile_name())
        qt4tools.set_font_bold(self.menuProfileName)
        self.contextMenu.addSeparator()

        self.menuStatusMessage = self.contextMenu.addAction(_('Done'))
        self.menuProgress = self.contextMenu.addAction('')
        self.menuProgress.setVisible(False)
        self.contextMenu.addSeparator()

        self.btnDecode = self.contextMenu.addAction(icon.VIEW_SNAPSHOT_LOG, _('decode paths'))
        self.btnDecode.setCheckable(True)
        self.btnDecode.setVisible(self.config.get_snapshots_mode() == 'ssh_encfs')
        QObject.connect(self.btnDecode, SIGNAL('toggled(bool)'), self.onBtnDecode)

        self.openLog = self.contextMenu.addAction(icon.VIEW_LAST_LOG, _('View Last Log'))
        QObject.connect(self.openLog, SIGNAL('triggered()'), self.onOpenLog)
        self.startBIT = self.contextMenu.addAction(icon.BIT_LOGO, _('Start BackInTime'))
        QObject.connect(self.startBIT, SIGNAL('triggered()'), self.onStartBIT)
        self.status_icon.setContextMenu(self.contextMenu)

        self.pixmap = icon.BIT_LOGO.pixmap(24)
        self.progressBar = QProgressBar()
        self.progressBar.setMinimum(0)
        self.progressBar.setMaximum(100)
        self.progressBar.setValue(0)
        self.progressBar.setTextVisible(False)
        self.progressBar.resize(24, 6)
        self.progressBar.render(self.pixmap, sourceRegion = QRegion(0, -14, 24, 6), flags = QWidget.RenderFlags(QWidget.DrawChildren))

        self.first_error = self.config.is_notify_enabled()
        self.popup = None
        self.last_message = None

        self.timer = QTimer()
        QObject.connect( self.timer, SIGNAL('timeout()'), self.update_info )

        self.ppid = os.getppid()

    def prepare_exit( self ):
        self.timer.stop()

        if not self.status_icon is None:
            self.status_icon.hide()
            self.status_icon = None

        if not self.popup is None:
            self.popup.deleteLater()
            self.popup = None

        self.qapp.processEvents()

    def run( self ):
        self.status_icon.show()
        self.timer.start( 500 )

        logger.info("[qt4systrayicon] begin loop", self)

        self.qapp.exec_()

        logger.info("[qt4systrayicon] end loop", self)

        self.prepare_exit()

    def update_info( self ):
        if not tools.is_process_alive( self.ppid ):
            self.prepare_exit()
            self.qapp.exit(0)
            return

        message = self.snapshots.get_take_snapshot_message()
        if message is None and self.last_message is None:
            message = ( 0, _('Working...') )

        if not message is None:
            if message != self.last_message:
                self.last_message = message
                if self.decode:
                    message = (message[0], self.decode.log(message[1]))
                self.menuStatusMessage.setText('\n'.join(tools.wrap_line(message[1],\
                                                                         size = 80,\
                                                                         delimiters = '',\
                                                                         new_line_indicator = '') \
                                                                        ))
                self.status_icon.setToolTip(message[1])

        pg = progress.ProgressFile(self.config)
        if pg.isFileReadable():
            pg.load()
            percent = pg.get_int_value('percent')
            if percent != self.progressBar.value():
                self.progressBar.setValue(percent)
                self.progressBar.render(self.pixmap, sourceRegion = QRegion(0, -14, 24, 6), flags = QWidget.RenderFlags(QWidget.DrawChildren))
                self.status_icon.setIcon(QIcon(self.pixmap))

            self.menuProgress.setText(' | '.join(self.getMenuProgress(pg)) )
            self.menuProgress.setVisible(True)
        else:
            self.status_icon.setIcon(self.icon.BIT_LOGO)
            self.menuProgress.setVisible(False)


    def getMenuProgress(self, pg):
        d = (('sent',   _('Sent:')), \
             ('speed',  _('Speed:')),\
             ('eta',    _('ETA:')) )
        for key, txt in d:
            value = pg.get_str_value(key, '')
            if not value:
                continue
            yield txt + ' ' + value

    def onStartBIT(self):
        profileID = self.config.get_current_profile()
        cmd = ['backintime-qt4',]
        if not profileID == '1':
            cmd += ['--profile-id', profileID]
        proc = subprocess.Popen(cmd)

    def onOpenLog(self):
        dlg = logviewdialog.LogViewDialog(self, systray = True)
        dlg.decode = self.decode
        dlg.cb_decode.setChecked(self.btnDecode.isChecked())
        dlg.exec_()

    def onBtnDecode(self, checked):
        if checked:
            self.decode = encfstools.Decode(self.config)
            self.last_message = None
            self.update_info()
        else:
            self.decode = None
    def __init__(self, parent=None):
        " Initialize QWidget inside MyMainWindow "
        super(MyMainWindow, self).__init__(parent)
        QWidget.__init__(self)
        self.statusBar().showMessage("               {}".format(__doc__))
        self.setStyleSheet("QStatusBar{color:grey;}")
        self.setWindowTitle(__doc__)
        self.setWindowIcon(QIcon.fromTheme("face-monkey"))
        self.setFont(QFont("Ubuntu Light", 10))
        self.setMaximumSize(QDesktopWidget().screenGeometry().width(), QDesktopWidget().screenGeometry().height())

        # directory auto completer
        self.completer = QCompleter(self)
        self.dirs = QDirModel(self)
        self.dirs.setFilter(QDir.AllEntries | QDir.NoDotAndDotDot)
        self.completer.setModel(self.dirs)
        self.completer.setCaseSensitivity(Qt.CaseInsensitive)
        self.completer.setCompletionMode(QCompleter.PopupCompletion)

        # Proxy support, by reading http_proxy os env variable
        proxy_url = QUrl(environ.get("http_proxy", ""))
        QNetworkProxy.setApplicationProxy(
            QNetworkProxy(
                QNetworkProxy.HttpProxy if str(proxy_url.scheme()).startswith("http") else QNetworkProxy.Socks5Proxy,
                proxy_url.host(),
                proxy_url.port(),
                proxy_url.userName(),
                proxy_url.password(),
            )
        ) if "http_proxy" in environ else None
        print((" INFO: Proxy Auto-Config as " + str(proxy_url)))

        # basic widgets layouts and set up
        self.mainwidget = QTabWidget()
        self.mainwidget.setToolTip(__doc__)
        self.mainwidget.setContextMenuPolicy(Qt.CustomContextMenu)
        self.mainwidget.tabCloseRequested.connect(lambda: self.mainwidget.setTabPosition(randint(0, 3)))
        # if self.mainwidget.tabPosition() == 0
        # else self.mainwidget.setTabPosition(0))
        self.mainwidget.setStyleSheet("QTabBar{color:white;font-weight:bold;}")
        self.mainwidget.setTabBar(TabBar(self))
        self.mainwidget.setMovable(True)
        self.mainwidget.setTabsClosable(True)
        self.mainwidget.setTabShape(QTabWidget.Triangular)
        self.setCentralWidget(self.mainwidget)
        self.dock1 = QDockWidget()
        self.dock2 = QDockWidget()
        self.dock3 = QDockWidget()
        for a in (self.dock1, self.dock2, self.dock3):
            a.setWindowModality(Qt.NonModal)
            a.setWindowOpacity(0.9)
            a.setWindowTitle(__doc__ if a.windowTitle() == "" else a.windowTitle())
            a.setStyleSheet(" QDockWidget::title{text-align:center;}")
            self.mainwidget.addTab(a, QIcon.fromTheme("face-smile"), "Double Click Me")

        # Paleta de colores para pintar transparente
        self.palette().setBrush(QPalette.Base, Qt.transparent)
        self.setPalette(self.palette())
        self.setAttribute(Qt.WA_OpaquePaintEvent, False)

        # toolbar and basic actions
        self.toolbar = QToolBar(self)
        self.toolbar.setIconSize(QSize(24, 24))
        # spacer widget for left
        self.left_spacer = QWidget(self)
        self.left_spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        # spacer widget for right
        self.right_spacer = QWidget(self)
        self.right_spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        qaqq = QAction(QIcon.fromTheme("application-exit"), "Quit", self)
        qaqq.setShortcut("Ctrl+Q")
        qaqq.triggered.connect(exit)
        qamin = QAction(QIcon.fromTheme("go-down"), "Minimize", self)
        qamin.triggered.connect(lambda: self.showMinimized())
        qamax = QAction(QIcon.fromTheme("go-up"), "Maximize", self)
        qanor = QAction(QIcon.fromTheme("view-fullscreen"), "AutoCenter AutoResize", self)
        qanor.triggered.connect(self.center)
        qatim = QAction(QIcon.fromTheme("mail-signed-verified"), "View Date and Time", self)
        qatim.triggered.connect(self.timedate)
        qabug = QAction(QIcon.fromTheme("help-about"), "Report a Problem", self)
        qabug.triggered.connect(
            lambda: qabug.setDisabled(True)
            if not call("xdg-open mailto:" + "*****@*****.**".decode("rot13"), shell=True)
            else " ERROR "
        )
        qamax.triggered.connect(lambda: self.showMaximized())
        qaqt = QAction(QIcon.fromTheme("help-about"), "About Qt", self)
        qaqt.triggered.connect(lambda: QMessageBox.aboutQt(self))
        qakde = QAction(QIcon.fromTheme("help-about"), "About KDE", self)
        if KDE:
            qakde.triggered.connect(KHelpMenu(self, "", False).aboutKDE)
        qaslf = QAction(QIcon.fromTheme("help-about"), "About Self", self)
        if KDE:
            qaslf.triggered.connect(KAboutApplicationDialog(aboutData, self).exec_)
        else:
            qaslf.triggered.connect(
                lambda: QMessageBox.about(
                    self.mainwidget,
                    __doc__,
                    "".join(
                        (
                            __doc__,
                            linesep,
                            "version ",
                            __version__,
                            ", (",
                            __license__,
                            "), by ",
                            __author__,
                            ", ( ",
                            __email__,
                            " )",
                            linesep,
                        )
                    ),
                )
            )
        qafnt = QAction(QIcon.fromTheme("tools-check-spelling"), "Set GUI Font", self)
        if KDE:
            font = QFont()
            qafnt.triggered.connect(
                lambda: self.setStyleSheet(
                    "".join(("*{font-family:", str(font.toString()), "}"))
                    if KFontDialog.getFont(font)[0] == QDialog.Accepted
                    else ""
                )
            )
        else:
            qafnt.triggered.connect(
                lambda: self.setStyleSheet("".join(("*{font-family:", str(QFontDialog.getFont()[0].toString()), "}")))
            )
        qasrc = QAction(QIcon.fromTheme("applications-development"), "View Source Code", self)
        qasrc.triggered.connect(lambda: call("xdg-open {}".format(__file__), 1))
        qakb = QAction(QIcon.fromTheme("input-keyboard"), "Keyboard Shortcuts", self)
        qakb.triggered.connect(
            lambda: QMessageBox.information(self.mainwidget, "Keyboard Shortcuts", " Ctrl+Q = Quit ")
        )
        qapic = QAction(QIcon.fromTheme("camera-photo"), "Take a Screenshot", self)
        qapic.triggered.connect(
            lambda: QPixmap.grabWindow(QApplication.desktop().winId()).save(
                QFileDialog.getSaveFileName(
                    self.mainwidget, " Save Screenshot As ...", path.expanduser("~"), ";;(*.png) PNG", "png"
                )
            )
        )
        qatb = QAction(QIcon.fromTheme("go-top"), "Toggle ToolBar", self)
        qatb.triggered.connect(lambda: self.toolbar.hide() if self.toolbar.isVisible() is True else self.toolbar.show())
        qati = QAction(QIcon.fromTheme("help-browser"), "Switch ToolBar Icon Size", self)
        qati.triggered.connect(
            lambda: self.toolbar.setIconSize(self.toolbar.iconSize() * 4)
            if self.toolbar.iconSize().width() * 4 == 24
            else self.toolbar.setIconSize(self.toolbar.iconSize() / 4)
        )
        qasb = QAction(QIcon.fromTheme("zoom-in"), "Toggle Tabs Bar", self)
        qasb.triggered.connect(
            lambda: self.mainwidget.tabBar().hide()
            if self.mainwidget.tabBar().isVisible() is True
            else self.mainwidget.tabBar().show()
        )
        qadoc = QAction(QIcon.fromTheme("help-browser"), "On-line Docs", self)
        qadoc.triggered.connect(lambda: open_new_tab(__url__))
        qapy = QAction(QIcon.fromTheme("help-about"), "About Python", self)
        qapy.triggered.connect(lambda: open_new_tab("http://python.org/about"))
        qali = QAction(QIcon.fromTheme("help-browser"), "Read Licence", self)
        qali.triggered.connect(lambda: open_new_tab(__full_licence__))
        qacol = QAction(QIcon.fromTheme("preferences-system"), "Set GUI Colors", self)
        if KDE:
            color = QColor()
            qacol.triggered.connect(
                lambda: self.setStyleSheet("".join(("* { background-color: ", str(color.name()), "}")))
                if KColorDialog.getColor(color, self)
                else ""
            )
        else:
            qacol.triggered.connect(
                lambda: self.setStyleSheet(
                    "".join((" * { background-color: ", str(QColorDialog.getColor().name()), " } "))
                )
            )
        qatit = QAction(QIcon.fromTheme("preferences-system"), "Set the App Window Title", self)
        qatit.triggered.connect(self.seTitle)
        self.toolbar.addWidget(self.left_spacer)
        self.toolbar.addSeparator()
        for b in (
            qaqq,
            qamin,
            qanor,
            qamax,
            qasrc,
            qakb,
            qacol,
            qatim,
            qatb,
            qafnt,
            qati,
            qasb,
            qatit,
            qapic,
            qadoc,
            qali,
            qaslf,
            qaqt,
            qakde,
            qapy,
            qabug,
        ):
            self.toolbar.addAction(b)
        self.addToolBar(Qt.TopToolBarArea, self.toolbar)
        self.toolbar.addSeparator()
        self.toolbar.addWidget(self.right_spacer)
        # define the menu
        menu = self.menuBar()
        # File menu items
        menu.addMenu("&File").addActions((qaqq,))
        menu.addMenu("&Window").addActions((qamax, qanor, qamin))
        # Settings menu
        menu.addMenu("&Settings").addActions((qasrc, qacol, qafnt, qatim, qatb, qati, qasb, qapic))
        # Help menu items
        menu.addMenu("&Help").addActions((qadoc, qakb, qabug, qali, qaqt, qakde, qapy, qaslf))
        # Tray Icon
        tray = QSystemTrayIcon(QIcon.fromTheme("face-devilish"), self)
        tray.setToolTip(__doc__)
        traymenu = QMenu()
        traymenu.addActions((qamax, qanor, qamin, qaqq))
        tray.setContextMenu(traymenu)
        tray.show()

        def contextMenuRequested(point):
            " quick and dirty custom context menu "
            menu = QMenu()
            menu.addActions(
                (
                    qaqq,
                    qamin,
                    qanor,
                    qamax,
                    qasrc,
                    qakb,
                    qacol,
                    qafnt,
                    qati,
                    qasb,
                    qatb,
                    qatim,
                    qatit,
                    qapic,
                    qadoc,
                    qali,
                    qaslf,
                    qaqt,
                    qakde,
                    qapy,
                    qabug,
                )
            )
            menu.exec_(self.mapToGlobal(point))

        self.mainwidget.customContextMenuRequested.connect(contextMenuRequested)

        def must_be_checked(widget_list):
            " widget tuple passed as argument should be checked as ON "
            for each_widget in widget_list:
                try:
                    each_widget.setChecked(True)
                except:
                    pass

        def must_have_tooltip(widget_list):
            " widget tuple passed as argument should have tooltips "
            for each_widget in widget_list:
                try:
                    each_widget.setToolTip(each_widget.text())
                except:
                    each_widget.setToolTip(each_widget.currentText())
                finally:
                    each_widget.setCursor(QCursor(Qt.PointingHandCursor))

        def must_autofillbackground(widget_list):
            " widget tuple passed as argument should have filled background "
            for each_widget in widget_list:
                try:
                    each_widget.setAutoFillBackground(True)
                except:
                    pass

        def must_glow(widget_list):
            " apply an glow effect to the widget "
            for glow, each_widget in enumerate(widget_list):
                try:
                    if each_widget.graphicsEffect() is None:
                        glow = QGraphicsDropShadowEffect(self)
                        glow.setOffset(0)
                        glow.setBlurRadius(99)
                        glow.setColor(QColor(99, 255, 255))
                        each_widget.setGraphicsEffect(glow)
                        # glow.setEnabled(False)
                        try:
                            each_widget.clicked.connect(
                                lambda: each_widget.graphicsEffect().setEnabled(True)
                                if each_widget.graphicsEffect().isEnabled() is False
                                else each_widget.graphicsEffect().setEnabled(False)
                            )
                        except:
                            each_widget.sliderPressed.connect(
                                lambda: each_widget.graphicsEffect().setEnabled(True)
                                if each_widget.graphicsEffect().isEnabled() is False
                                else each_widget.graphicsEffect().setEnabled(False)
                            )
                except:
                    pass

        #######################################################################

        self.group1 = QGroupBox()
        self.group1.setTitle(__doc__)
        self.frmt = QComboBox(self.group1)
        self.frmt.addItems(["blah ", "blah blah", "blah blah blah"])
        self.file1 = QLineEdit()
        self.file1.setPlaceholderText("/full/path/to/one_file.py")
        self.file1.setCompleter(self.completer)
        self.borig = QPushButton(QIcon.fromTheme("folder-open"), "Open")
        vboxg1 = QVBoxLayout(self.group1)
        for each_widget in (
            QLabel('<b style="color:white;">some comment'),
            self.file1,
            self.borig,
            QLabel('<b style="color:white;">Lorem Impsum'),
            self.frmt,
        ):
            vboxg1.addWidget(each_widget)

        self.group2 = QGroupBox()
        self.group2.setTitle(__doc__)
        self.nwfl = QCheckBox("Be Awesome")
        self.smll = QCheckBox("Solve the Squaring of the Circle")
        self.lrgf = QCheckBox("Im just a QCheckBox")
        self.case = QCheckBox("Use Quantum Processing")
        vboxg2 = QVBoxLayout(self.group2)
        for each_widget in (self.nwfl, self.smll, self.lrgf, self.case):
            vboxg2.addWidget(each_widget)

        group3 = QGroupBox()
        group3.setTitle(__doc__)
        self.plai = QCheckBox("May the Force be with You")
        self.nocr = QCheckBox("Im just a Place Holder")
        self.ridt = QCheckBox("Lorem Impsum")
        self.nocm = QCheckBox("Divide by Zero")
        vboxg3 = QVBoxLayout(group3)
        for each_widget in (self.plai, self.nocr, self.ridt, self.nocm):
            vboxg3.addWidget(each_widget)
        container = QWidget()
        hbox = QHBoxLayout(container)
        for each_widget in (self.group2, self.group1, group3):
            hbox.addWidget(each_widget)
        self.dock1.setWidget(container)

        # dock 2
        self.dock2.setWidget(QPlainTextEdit())

        # dock 3
        self.dock3.setWidget(QCalendarWidget())

        # configure some widget settings
        must_be_checked((self.nwfl, self.smll, self.lrgf, self.plai))
        must_have_tooltip((self.plai, self.nocr, self.ridt, self.nocm, self.nwfl, self.smll, self.lrgf, self.case))
        must_autofillbackground(
            (self.plai, self.nocr, self.ridt, self.nocm, self.nwfl, self.smll, self.lrgf, self.case)
        )
        must_glow((self.plai, self.nocr, self.ridt, self.nocm, self.nwfl))
示例#17
0
class Qt4SysTrayIcon:
    def __init__(self):
        self.snapshots = snapshots.Snapshots()
        self.config = self.snapshots.config

        if len(sys.argv) > 1:
            if not self.config.set_current_profile(sys.argv[1]):
                logger.warning("Failed to change Profile_ID %s" % sys.argv[1],
                               self)

        self.qapp = qt4tools.create_qapplication(self.config.APP_NAME)

        import icon
        self.icon = icon
        self.qapp.setWindowIcon(icon.BIT_LOGO)

        self.status_icon = QSystemTrayIcon(icon.BIT_LOGO)
        #self.status_icon.actionCollection().clear()
        self.contextMenu = QMenu()

        self.menuProfileName = self.contextMenu.addAction(
            _('Profile: "%s"') % self.config.get_profile_name())
        qt4tools.set_font_bold(self.menuProfileName)
        self.contextMenu.addSeparator()

        self.menuStatusMessage = self.contextMenu.addAction(_('Done'))
        self.menuProgress = self.contextMenu.addAction('')
        self.menuProgress.setVisible(False)
        self.contextMenu.addSeparator()
        self.startBIT = self.contextMenu.addAction(icon.BIT_LOGO,
                                                   _('Start BackInTime'))
        QObject.connect(self.startBIT, SIGNAL('triggered()'), self.onStartBIT)
        self.status_icon.setContextMenu(self.contextMenu)

        self.pixmap = icon.BIT_LOGO.pixmap(24)
        self.progressBar = QProgressBar()
        self.progressBar.setMinimum(0)
        self.progressBar.setMaximum(100)
        self.progressBar.setValue(0)
        self.progressBar.setTextVisible(False)
        self.progressBar.resize(24, 6)
        self.progressBar.render(self.pixmap,
                                sourceRegion=QRegion(0, -14, 24, 6),
                                flags=QWidget.RenderFlags(
                                    QWidget.DrawChildren))

        self.first_error = self.config.is_notify_enabled()
        self.popup = None
        self.last_message = None

        self.timer = QTimer()
        QObject.connect(self.timer, SIGNAL('timeout()'), self.update_info)

        self.ppid = os.getppid()

    def prepare_exit(self):
        self.timer.stop()

        if not self.status_icon is None:
            self.status_icon.hide()
            self.status_icon = None

        if not self.popup is None:
            self.popup.deleteLater()
            self.popup = None

        self.qapp.processEvents()

    def run(self):
        self.status_icon.show()
        self.timer.start(500)

        logger.info("[qt4systrayicon] begin loop", self)

        self.qapp.exec_()

        logger.info("[qt4systrayicon] end loop", self)

        self.prepare_exit()

    def update_info(self):
        if not tools.is_process_alive(self.ppid):
            self.prepare_exit()
            self.qapp.exit(0)
            return

        message = self.snapshots.get_take_snapshot_message()
        if message is None and self.last_message is None:
            message = (0, _('Working...'))

        if not message is None:
            if message != self.last_message:
                self.last_message = message
                self.menuStatusMessage.setText('\n'.join(tools.wrap_line(self.last_message[1],\
                                                                         size = 80,\
                                                                         delimiters = '',\
                                                                         new_line_indicator = '') \
                                                                        ))
                self.status_icon.setToolTip(self.last_message[1])

        pg = progress.ProgressFile(self.config)
        if pg.isFileReadable():
            pg.load()
            percent = pg.get_int_value('percent')
            if percent != self.progressBar.value():
                self.progressBar.setValue(percent)
                self.progressBar.render(self.pixmap,
                                        sourceRegion=QRegion(0, -14, 24, 6),
                                        flags=QWidget.RenderFlags(
                                            QWidget.DrawChildren))
                self.status_icon.setIcon(QIcon(self.pixmap))

            self.menuProgress.setText(' | '.join(self.getMenuProgress(pg)))
            self.menuProgress.setVisible(True)
        else:
            self.status_icon.setIcon(self.icon.BIT_LOGO)
            self.menuProgress.setVisible(False)

    def getMenuProgress(self, pg):
        d = (('sent',   _('Sent:')), \
             ('speed',  _('Speed:')),\
             ('eta',    _('ETA:')) )
        for key, txt in d:
            value = pg.get_str_value(key, '')
            if not value:
                continue
            yield txt + ' ' + value

    def onStartBIT(self):
        profileID = self.config.get_current_profile()
        cmd = [
            'backintime-qt4',
        ]
        if not profileID == '1':
            cmd += ['--profile-id', profileID]
        proc = subprocess.Popen(cmd)
示例#18
0
  except dbus.exceptions.DBusException:
    QMessageBox.critical(None, "Can't connect",
                        """Can't connect to pyUmlaut0r daemon.\nYou should first start a daemon by calling:\n'pyUmlaut0r.py -d'.""")
    print "can't connect to daemon"
    sys.exit(1)


#set process name
utils.setProcessName("pyUmlaut0r")

#create trayIcon
trayIcon = QSystemTrayIcon()
trayIcon.setIcon(QIcon(":/pyUmlaut0rIcon.png"))
trayIcon.setContextMenu(utils.createMenu())
trayIcon.show()

#dbus "daemon"
DBusQtMainLoop(set_as_default = True)

class DBusInterface(dbus.service.Object):
  def __init__(self):
    busName = dbus.service.BusName('org.documentroot.umlaut0r', \
                                   bus = dbus.SessionBus())
    dbus.service.Object.__init__(self, busName, '/umlaut0r')

  @dbus.service.method('org.documentroot.umlaut0r', in_signature='s')
  def toClipboard(self, s):
    utils.toClipboard(s)

dbusInterface = DBusInterface()
示例#19
0
class SessionTesterWindow(QMainWindow, Ui_MainAppWindow):

    progress_bar_change = QtCore.pyqtSignal()
    session_end = QtCore.pyqtSignal()

    def __init__(self):
        QMainWindow.__init__(self)

        self.isStarted = False
        self.isPaused = True
        self.isRIP = False
        self.current_time = 0

        self.tray_icon = QSystemTrayIcon(QIcon("sessiontester/resources/trayicon.xpm"))
        self.tray_icon.activated.connect(self.maximize_window)
        self.tray_icon.show()
        self.session_end.connect(self.session_end_message)

        self.setupUi(self)
        self.sessionStartButton.clicked.connect(self.start_session)
        self.newSessionButton.clicked.connect(self.new_session)
        self.exportSessionButton.clicked.connect(self.export_session)
        self.settingsButton.clicked.connect(self.open_settings)

        self.progressBar.setTextVisible(True)
        self.progressBar.setFormat("Session progress")
        self.session_config = SessionConfig(os.path.join(os.path.expanduser('~'),'sessiontester','config.ini'))

    def start_session(self):
        self.session_time = self.__count_session_time(
            self.sessionTimeField.time().toString("hh:mm:ss"))
        if (self.isPaused is True) & (self.session_time > 0):
            self.isPaused = False
            self.sessionStartButton.setText("Pause session")
            self.session_time = self.__count_session_time(
                self.sessionTimeField.time().toString("hh:mm:ss"))
            self.progressBar.setMaximum(self.session_time)
            if self.isRIP is True:
                self.progressBar.setValue(0)
                self.current_time = 0
                self.isRIP = False
            self.progress_bar_change.connect(self.set_progress_bar)
            self.t = threading.Thread(target=self.set_progress)
            self.t.daemon = True
            self.t.start()
        else:
            self.sessionStartButton.setText("Start session")
            self.isPaused = True

    def new_session(self):
        self.progressBar.setValue(0)
        self.progressBar.setFormat("Session progress")
        self.sessionStartButton.setText("Start session")
        self.current_time = 0
        self.isPaused = True

    def export_session(self):
        export_session.export_session_to_html(self.textEdit.toPlainText(), self.session_config)

    def set_progress_bar(self):
        self.progressBar.setValue(self.current_time)
        self.progressBar.setFormat("Time left:" + str(
            datetime.timedelta(seconds=self.time_to_go)))

    def session_end_message(self):
        self.tray_icon.showMessage("Session is over!", "Session time is over")
        self.sessionStartButton.setText("Start session")
        self.progressBar.setFormat("Session is over!")
        self.isPaused = True
        self.isRIP = True

    def set_progress(self):
        while (self.current_time < self.session_time):
            if self.isPaused is False:
                time.sleep(1)
            else:
                break
            if self.isPaused is False:
                self.current_time = self.current_time + 1
                self.progress_bar_change.emit()
                self.time_to_go = self.session_time - self.current_time
        if self.current_time == self.session_time:
            self.session_end.emit()

    def __count_session_time(self, time_string):
        self.result_date = time_string.split(":")
        return (int(self.result_date[0])*3600) + (int(self.result_date[1])*60) + int(self.result_date[2])

    def maximize_window(self):
        if self.isHidden() is False:
            self.hide()
        elif self.isHidden() is True:
            self.show()

    def open_settings(self):
        self.settings = SettingsWindow(self)
        self.settings.show()
示例#20
0
class Terminals(QWidget):
    ready = pyqtSignal(bool)

    def __init__(self, parent=None):
        QWidget.__init__(self, parent)

        self.ui = uic.loadUiType('terminal.ui')[0]()
        self.ui.setupUi(self)

        self.notifier = QSystemTrayIcon(QIcon('arrow-up-icon.png'), self)
        self.notifier.show()

        self.model = None
        self.mainloop = None
        self.delegate = None

    def test_display(self):
        if self.mainloop:
            self.mainloop.test_display()

    def update_device_config(self):
        if self.mainloop:
            self.mainloop.update_config()

    def terminal_open(self, addr):
        if self.mainloop:
            self.mainloop.terminal_open(addr)

    def terminal_close(self, addr):
        if self.mainloop:
            self.mainloop.terminal_close(addr)

    def start_mainloop(self):
        if self.mainloop is None:
            self.mainloop = Mainloop(parent=self)
            self.mainloop.ready.connect(self.on_mainloop_ready)
            self.mainloop.notify.connect(lambda title, msg: self.notifier.showMessage(title, msg))
            self.mainloop.start()

    def stop_mainloop(self):
        if self.mainloop:
            self.mainloop.state.disconnect()
            self.mainloop.ready.disconnect()
            self.mainloop.notify.disconnect()

            [self.ui.terminals.closePersistentEditor(self.model.index(row, 0))
             for row in xrange(self.model.rowCount())]
            self.mainloop.stop()

            self.mainloop = None

    def update_model(self):
        self.stop_mainloop()
        self.start_mainloop()

    def on_mainloop_ready(self, ok, titles):
        if ok:
            self.model = QStandardItemModel(len(titles), 1)
            [self.model.setItem(i, QStandardItem(str(addr))) for i, addr in enumerate(titles.keys())]

            self.delegate = TerminalDelegate(self.mainloop, titles)
            self.mainloop.report.connect(self.delegate.report)
            self.mainloop.state.connect(self.delegate.state)

            self.ui.terminals.setModel(self.model)
            self.ui.terminals.setItemDelegateForColumn(0, self.delegate)
            [self.ui.terminals.openPersistentEditor(self.model.index(row, 0))
             for row in xrange(self.model.rowCount())]

            self.mainloop.db.free_places_update.connect(self.ui.free_places.setValue)
            self.mainloop.update_config()
        else:
            self.model = None
            self.mainloop = None

        self.ready.emit(ok)
示例#21
0
文件: window.py 项目: ThePsyjo/PyWv
class MainWindow(QMainWindow):
	def __init__(self):
		QMainWindow.__init__(self)
		
		self.setWindowTitle('%s %s' % (QApplication.applicationName(), QApplication.applicationVersion()));

		self.config = ConfigHandler(os.path.join(os.path.expanduser('~'), '.pywv/pywv.cfg'), self)

		self.setStyle(QStyleFactory.create(self.config.loadStyle()))
		if self.config.loadStyleSheet():
			self.setStyleSheet(self.config.loadStyleSheet())
		else:
			self.setStyleSheet("* {}") # without any stylesheet, windowstyles won't apply


		self.setDockOptions(QMainWindow.AnimatedDocks | QMainWindow.AllowNestedDocks | QMainWindow.AllowTabbedDocks | QMainWindow.VerticalTabs);

#		self.dummy = QWidget(self)
		self.setCentralWidget(QWidget(self))

		self.pBar = QProgressBar(self)
		self.pBar.setRange(0, self.config.loadReloadInterval())
		self.pBar.setFormat("%v Sekunden")
		if not self.config.loadAutoload():
			self.pBar.hide()

		self.statusBar = QStatusBar(self)
		self.setStatusBar(self.statusBar)
		self.statusBar.addWidget(self.pBar)

		self.reloadTimer = QTimer(self);
		self.reloadTimer.setInterval(self.config.loadReloadInterval() * 1000)
		self.connect(self.reloadTimer, SIGNAL('timeout()'), self.reload_)
		if self.config.loadAutoload():
			self.reloadTimer.start()

		self.autoloadStatusTimer = QTimer(self)
		self.autoloadStatusTimer.setInterval(1000) # 1 sec
		self.connect(self.autoloadStatusTimer, SIGNAL('timeout()'), self.onAutoloadStatus)
		self.autoloadStatusTimer.start()

		self.mAction = self.menuBar().addMenu(self.tr("&Action"))
		self.mAction.addAction(self.tr("&update"), self.reload_, QKeySequence('F5'))
		self.mAction.addAction(self.tr("e&xit"), self.onExit, 'Ctrl+Q')

		self.mStyle = QMenu(self.tr("&Style"), self)
		for s in list(QStyleFactory.keys()):#       // fill in all available Styles
			self.mStyle.addAction(s)
		self.connect(self.mStyle, SIGNAL('triggered(QAction*)'), self.onStyleMenu)

		self.mOption = self.menuBar().addMenu(self.tr("&Options"))
		self.mOption.addAction(self.tr("reloadinterval") , self.onReloadTime , 'F8')
		self.mOption.addAction(self.tr("manage links")   , self.onNewLink    , 'F6')
		self.mOption.addSeparator()

		self.ontopAction       = QAction(self.tr("always on &top")  , self)
		self.showTrayAction    = QAction(self.tr("show tray &icon") , self)
		self.closeToTrayAction = QAction(self.tr("close to &tray")  , self)
		self.autoloadAction    = QAction(self.tr("auto&load")       , self)

		self.ontopAction.setCheckable(True)
		self.showTrayAction.setCheckable(True)
		self.closeToTrayAction.setCheckable(True)
		self.autoloadAction.setCheckable(True)

		self.showTrayAction.setChecked   (self.config.loadShowTray()   )
		self.ontopAction.setChecked      (self.config.loadOntop()      )
		self.closeToTrayAction.setChecked(self.config.loadCloseToTray())
		self.autoloadAction.setChecked   (self.config.loadAutoload()   )

		self.connect(self.ontopAction       , SIGNAL('toggled(bool)') , self.onOntopAction)
		self.connect(self.showTrayAction    , SIGNAL('toggled(bool)') , self.onShowTrayAction)
		self.connect(self.closeToTrayAction , SIGNAL('toggled(bool)') , self.onCloseToTrayAction)
		self.connect(self.autoloadAction    , SIGNAL('toggled(bool)') , self.onAutoloadAction)

		self.mOption.addAction(self.ontopAction)
		self.mOption.addAction(self.showTrayAction)
		self.mOption.addAction(self.closeToTrayAction)
		self.mOption.addAction(self.autoloadAction)
		self.mOption.addSeparator()
		self.mOption.addMenu(self.mStyle)

		self.trayIcon = QSystemTrayIcon(QIcon(':/appicon'), self);
		self.trayMgr = TrayManager(self.config, self.trayIcon)
		self.connect(self.trayIcon, SIGNAL('activated(QSystemTrayIcon::ActivationReason)'), self.onTrayIcon)
		if self.config.loadShowTray(): self.trayIcon.show()

		self.trayIconMenu = QMenu()
		self.trayIconMenu.addAction(self.tr("e&xit"), self.onExit)
		self.trayIcon.setContextMenu(self.trayIconMenu)

		self.mAbout = self.menuBar().addMenu(self.tr("&about"))
		self.mAbout.addAction(QApplication.applicationName(), self.onAboutAppAction)
		self.mAbout.addAction("Qt", self.onAboutQtAction)

		self.createWidgets()

		self.resize(self.config.loadWindowSize())
		self.restoreState(self.config.loadWindowState())

		if self.config.loadIsVisible():
			self.show()
			self.reload_()

	def __del__(self):
		self.config.saveWindowState(self.saveState())

	def createSingleWidget(self, name):
#		print 'crt', name, type(name), '\n', self.widgets
#		print 'crt', name, type(name)
		links = self.config.loadLinks()
		if links[name]['type'] == 'generic':
			self.widgets[name] = GenericWidget(name, self.config, self)
		else:
			pluginsAvail = classdirPlugins().all_()
			for plugin in pluginsAvail:
				if links[name]['type'] == plugin['class']:
					pluginClass = plugin['class']
					break
				else:
					continue

			exec('self.widgets[name] = %s(name, self.config, self)' % pluginClass)
		#	print(('loaded plugin', self.widgets[name]))

		self.addDockWidget(0x4, self.widgets[name])
		self.widgets[name].reload_()

	def delWidget(self, name):
		#print 'del', name, type(name), '\n', self.widgets
		self.removeDockWidget(self.widgets[name])
		self.widgets[name].deleteLater()
		self.widgets[name] = None
		del self.widgets[name]

	def createWidgets(self):
		self.widgets = {}
		for name in self.config.loadLinks():
			self.createSingleWidget(name)


	@pyqtSlot()
	def onExit(self):
		self.config.saveWindowSize(self.size())
		QApplication.exit();

	def closeEvent(self, event):
		self.config.saveWindowSize(self.size())
#	       	QApplication.exit()
		# tray is visible -> close to tray
		# else close app
		if self.trayIcon.isVisible():
			event.accept()
		else:
			QApplication.exit()
			return
		# if close-to-tray is set, do so
		if self.config.loadCloseToTray():
			event.accept()
		else:
			QApplication.exit()
			return;
		# save this state
		if	self.trayIcon.isVisible():	self.config.saveIsVisible(False)
		else:					self.config.saveIsVisible(True);
	@pyqtSlot()
	def reload_(self):
		for name in self.widgets:
			self.widgets[name].reload_()
		self.pBar.setValue(self.config.loadReloadInterval())
		self.reloadTimer.start(self.config.loadReloadInterval()*1000)

	@pyqtSlot()
	def onAutoloadStatus(self):
		self.pBar.setValue(self.pBar.value()-1)
#		print([idx for idx in self.widgets])

	def onStyleMenu(self, a):
		QApplication.setStyle(QStyleFactory.create(a.text()))
		self.setStyle(QStyleFactory.create(a.text()))
		self.config.saveStyle(a.text())

	def onReloadTime(self):
		ok = False
		value, ok = QInputDialog.getInteger(self,
			self.tr("reloadinterval"), # title
			self.tr("insert time in s"), # text
			self.config.loadReloadInterval(), # default
			10, # minimum
			86400, # maximum (at least once a day)
			1, # step
			)
		if ok:
			self.config.saveReloadInterval(value)
			self.pBar.setRange(0,self.config.loadReloadInterval())
			self.reload_()

	def onAutoloadAction(self, b):
		if b:
			self.reloadTimer.start()
			self.pBar.show()
			self.reload_()
		else:
			self.reloadTimer.stop()
			self.pBar.hide()
		self.config.saveAutoload(b)

	def onNewLink(self):
		inp = LinkInput(self.config, self)
		if inp.exec_():
			# sync active widgets
			for name in inp.modifiedWidgets():
				if name in self.widgets:
					self.delWidget(name)
					self.createSingleWidget(name)
				else:
					self.createSingleWidget(name)

			# remove deleted
#			for name in self.widgets: print 'shown', name
#			for name in self.config.loadLinks(): print 'conf', name
			todel = []
			for name in self.widgets:
				if name not in self.config.loadLinks():
					todel.append(name)

			for widget in todel:
				self.delWidget(widget)

	def onOntopAction(self, b):
		if b:	self.setWindowFlags(Qt.Dialog | Qt.WindowStaysOnTopHint)
		else:	self.setWindowFlags(Qt.Dialog)
		self.setWindowIcon(QIcon(':/appicon'))
		self.show();
		self.config.saveOntop(b)

	def onShowTrayAction(self, b):
		if b:	self.trayIcon.show()
		else:	self.trayIcon.hide()
		self.config.saveShowTray(b)

	def onCloseToTrayAction(self, b):
		self.config.saveCloseToTray(b)

	def onTrayIcon(self, reason):
		if reason == QSystemTrayIcon.Trigger:
			if(self.isVisible()):
				self.config.saveWindowSize(self.size())
				self.hide()
				self.config.saveIsVisible(False)
			else:
				self.show()
				self.resize(self.config.loadWindowSize())
				self.config.saveIsVisible(True)

	def onAboutAppAction(self):
		QMessageBox.about(self, self.tr("&about"), self.tr("name %1 version %2").arg(QApplication.applicationName()).arg(QApplication.applicationVersion()))
	def onAboutQtAction(self):
		QMessageBox.aboutQt(self, self.tr("&about"))
示例#22
0
文件: run.py 项目: dmzkrsk/wol-tray
class MainWindow(QMainWindow):
    def __init__(self):
        QMainWindow.__init__(self)

        self.settings = QSettings(QSettings.IniFormat, QSettings.UserScope, VENDOR, APP)

        self.setup = ConfigDialog(None, Qt.WindowSystemMenuHint | Qt.WindowTitleHint)
        self.setup.setModal(True)
        centerOnScreen(self.setup)
        self.setup.wake.connect(self.wake)
        self.setup.serversChanged.connect(self.updateMenu)

        self.menuServers = []

        self.trayIcon = QSystemTrayIcon(QIcon("res/power.png"), self)
        self.trayIcon.activated.connect(self.activated)

        menu = QMenu()

        self.populateMenuFromSettings(menu)

        menu.addSeparator()

        self.setupAction = menu.addAction(QIcon('res/setup.png'), "Configure")
        self.setupAction.triggered.connect(self.setup.show)

        menu.addSeparator()

        exitAction = menu.addAction("Exit")
        exitAction.triggered.connect(self.close)

        self.trayIcon.setContextMenu(menu)

        self.trayIcon.setToolTip("Wake on LAN")

        self.trayIcon.show()

        servers = self.settings.beginReadArray("servers")
        self.settings.endArray()

        if not servers:
            self.setup.show()

    def populateMenuFromSettings(self, menu):
        """
        :type menu: QMenu
        """
        actions = menu.actions()
        before = actions[0] if actions else None

        title = QWidgetAction(menu)
        label = QLabel("Hosts")
        font = label.font()
        px = font.pointSize()
        font.setBold(True)
        font.setPointSize(px * 1.5)
        label.setFont(font)
        label.setMargin(4)
        label.setIndent(10)
        #        label.setStyleSheet("font-weight: bold; margin: 4px 2px; border-bottom: 2px solid black")
        title.setDefaultWidget(label)

        menu.insertAction(before, title)
        self.menuServers.append(title)

        servers = self.settings.beginReadArray("servers")
        for d in range(servers):
            self.settings.setArrayIndex(d)
            server = Server.fromSettings(self.settings)
            action = QAction(QIcon("res/server.png"), server.alias, menu)
            menu.insertAction(before, action)
            action.setData(server)
            action.triggered.connect(self.wakeFromMenu)
            self.menuServers.append(action)
        self.settings.endArray()

    def activated(self, reason):
        if reason == QSystemTrayIcon.DoubleClick:
            self.setup()
        elif reason == QSystemTrayIcon.Trigger:
            menu = QMenu()
            self.populateMenuFromSettings(menu)
            menu.exec_(QCursor.pos())

    def updateMenu(self):
        menu = self.trayIcon.contextMenu()
        for action in self.menuServers:
            action.setData(None)
            menu.removeAction(action)

        self.populateMenuFromSettings(menu)

    def wakeFromMenu(self):
        action = self.sender()
        server = action.data().toPyObject()
        self.wake(server)

    def wake(self, server):
        if QMessageBox.Yes == QMessageBox.question(self, "Wake on LAN", "Wake %s?" % server.alias, QMessageBox.Yes|QMessageBox.No):
            magic = '\xFF' * 6
            bits = str(server.mac).split(':')
            machex = ''.join([struct.pack('B', (int(x, 16))) for x in bits])
            magic += machex * 16

            sock = socket(type=SOCK_DGRAM)
            if server.broadcast:
                sock.setsockopt(SOL_SOCKET, SO_BROADCAST, 1)
            sock.sendto(magic, ('<broadcast>', server.port))
            sock.close()

            self.trayIcon.showMessage("Wake on LAN", "Magic packet was sent to %s" % server.alias, msecs=3000)

    def close(self):
        QApplication.quit()
for author in AUTHORS:
    name, email = author.rsplit(" ", 1)
    aboutData.addAuthor(ki18n(name), ki18n(""), email.strip("<>"), "")

KCmdLineArgs.init (sys.argv, aboutData)
app = KApplication()

import smart
ctrl = smart.init()

mainWindow = KMainWindow()
smart_icon = QIcon(getPixmap("smart"))
mainWindow.setWindowIcon(smart_icon)
sysTray = QSystemTrayIcon(smart_icon, None)
smart_image = getPixmap("smart").toImage()
aboutData.setProgramLogo(QVariant(smart_image))

menu = QMenu(None)
menu.addAction(KIcon("view-refresh"), "Check for updates", smart_update)
menu.addAction(smart_icon, "Launch Smart", smart_gui)
menu.addSeparator()
menu.addAction(KIcon("help-about"), "About", show_about)
menu.addAction(KIcon("application-exit"), "Quit", exit_applet)
sysTray.setContextMenu(menu)

sysTray.show()

app.exec_()

# vim:ts=4:sw=4:et
示例#24
0
文件: main.py 项目: arjunjain/nixurl
class MainWindow(QMainWindow,Ui_MainWindow):

    def __init__(self,parent=None):
        QMainWindow.__init__(self,parent)         
        self.setupUi(self)
        self.textshorturl.setEnabled(False)
        self.convertprogress.hide()        
        self.trayIcon = QSystemTrayIcon()
        self.trayIcon.setIcon(QIcon("/usr/share/pixmaps/nixiconsvg.svg"))
        trayIconMenu = QMenu()
        self.appabout = trayIconMenu.addAction("About")
        self.appexit = trayIconMenu.addAction("Exit")
        self.trayIcon.setContextMenu(trayIconMenu)       
        self.connect(self.trayIcon,SIGNAL("activated(QSystemTrayIcon::ActivationReason)"),self.iconActivated)
        self.connect(self.buttonurlconvert,SIGNAL('clicked()'),self.converturl)
        self.connect(self.appexit,SIGNAL('triggered()'),self.close)
        self.connect(self.appabout,SIGNAL('triggered()'),self.showabout)
        self.connect(self.actionAbout,SIGNAL('triggered()'),self.showabout)
        self.connect(self.buttonreset,SIGNAL('clicked()'),self.resetall)
        self.connect(self.actionNew,SIGNAL('triggered()'),self.resetall)
        
    
    def iconActivated(self,dovod):
        if dovod == QSystemTrayIcon.Trigger:
            if self.isVisible():
                self.hide()
            else:
                self.show()
                 
    def resetall(self):
        self.texturl.setText("")
        self.textshorturl.setText("")
        self.textshorturl.setEnabled(False)
        self.buttonurlconvert.setEnabled(True)
        self.comboservice.setCurrentIndex(0)
        self.convertprogress.hide()
        
    def converturl(self):
        url=str(self.texturl.text())
        url=url.strip()
        if url=="":
            QMessageBox.warning(self,"Error","Please Enter the valid URL")
        else:
            self.convertprogress.show()
            self.convertprogress.setValue(10)
            self.textshorturl.setEnabled(True)
            self.convertprogress.setValue(30)
            self.currentservice=self.comboservice.currentText()
            self.convertprogress.setValue(50)
            self.buttonurlconvert.setEnabled(False)
            if self.currentservice == "TinyURL":
                try:
                    self.textshorturl.setText(str(tinyurl.create_one(url)))
                    self.convertprogress.setValue(100)
                    self.buttonurlconvert.setEnabled(True)
                except:
                    QMessageBox.warning(self,"Error","Host can not be resolved")
                            
            elif self.currentservice == "google":
                try:
                    self.textshorturl.setText(str(google.shorten(url)))
                    self.convertprogress.setValue(100)
                    self.buttonurlconvert.setEnabled(True)
                    self.textshorturl.copy()
                except:
                    QMessageBox.warning(self,"Error","Host can not be resolved")
                    
            elif self.currentservice == "bit.ly":
                try:
                    a=bitly.Api()
                    self.textshorturl.setText(str(a.shorten(url)))
                    self.convertprogress.setValue(100)
                    self.buttonurlconvert.setEnabled(True)
                except:
                    QMessageBox.warning(self,"Error","Host can not be resolved")
    
    def showEvent(self,event):
        self.show()
        self.trayIcon.hide()
        event.ignore()
     
    def closeEvent(self,event):
        reply = QMessageBox.question(self, 'Message',"Are you sure to quit?", QMessageBox.Yes | QMessageBox.No,QMessageBox.No)
        if reply == QMessageBox.Yes:
            self.trayIcon.hide()
            event.accept()
        else:
            self.hide()
            self.trayIcon.show()
            event.ignore()  

    def showabout(self):
        ab=About()
        ab.exec_()
示例#25
0
    def __init__(self, parent=None):
        super(MainForm, self).__init__(parent)
        uic.loadUi("./MainWindow/form.ui", self)
        self.setWindowTitle("NFS-List")
        self.setLayout(self.gridLayout)
        self.setGeometry(100, 100, 640, 480)
        self.listWidget.setViewMode(QtGui.QListView.IconMode)
        self.listWidget.setMovement(QtGui.QListWidget.Static)
        self.ipv6_enable = True  # False
        self.addr_ipv4 = None
        self.addr_ipv6 = None
        self.addr_ipv4_array = []
        self.addr_ipv6_array = []
        self.time = 1

        self.hosts = []
        self.icon = QtGui.QIcon("./MainWindow/NAS-icon.png")
        self.setWindowIcon(self.icon)

        #Tray
        tray_menu = QtGui.QMenu(self)

        show_hide_action = QAction("Show/Hide", self)
        quitAction = QAction("Quit", self)

        tray_menu.addAction(show_hide_action)
        tray_menu.addAction(quitAction)

        tray = QSystemTrayIcon(self)
        tray.setIcon(self.icon)
        tray.setContextMenu(tray_menu)
        tray.setToolTip(self.windowTitle())
        tray.show()
        #
        show_hide_action.triggered.connect(self.showHideWindow)
        quitAction.triggered.connect(QtGui.qApp.quit)

        #end tray

        # self.ico.addPixmap(self.pixmap)
        ifaces = QtNetwork.QNetworkInterface.allInterfaces()
        for iface in ifaces:
            for addr_iface in iface.addressEntries():
                if addr_iface.ip() != QtNetwork.QHostAddress(QtNetwork.QHostAddress.LocalHost) and \
                                addr_iface.ip() != QtNetwork.QHostAddress(QtNetwork.QHostAddress.LocalHostIPv6):
                    if addr_iface.ip().toIPv4Address():
                        self.addr_ipv4_array.append(addr_iface)
                    if self.ipv6_enable:
                        if addr_iface.ip().toIPv6Address():
                            self.addr_ipv6_array.append(addr_iface)

        if len(self.addr_ipv4_array) >= 1:
            self.addr_ipv4 = self.addr_ipv4_array[0].ip().toString()

        #ip data#

        addr_mask = self.addr_ipv4_array[0].netmask().toString()
        #addr_mask = '255.255.255.192'

        __list_aprefix = addr_mask.split('.')
        cidr_ipv4 = 0
        bn = '0b'
        baddr = '0b'
        for i in __list_aprefix:
            cidr_ipv4 += rpclib.bit_count(int(i))
            bn += bin(int(i))[2:]

        print("cidr:", cidr_ipv4)
        print(bn)
        #
        total_ip_count = (2 ** (32 - cidr_ipv4)) - 2
        print('total_ip_count:', total_ip_count)
        print(self.addr_ipv4)
        int_net_ipv4 = rpclib.ip2int(self.addr_ipv4) & rpclib.ip2int(addr_mask)
        net_ipv4 = rpclib.int2ip(int_net_ipv4)


        #abc = ClockThread(self.time, self.add_new_item)
        #abc.start()
        #self.add_new_item('t34', 't32')

        self.scan_network = ThreadScanNetwork(10, net_ipv4, cidr_ipv4, self, 1.2)
        self.scan_network.start()

        self.check_host = ThreadCheckHost(self.hosts, self)
        self.check_host.start()

        #self.add_host({"host":"100.64.0.1","structures":[{'groups': [b'*'], 'dir': b'/srv/NFS'}]})
        """
        self.listWidget.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)

        self.actionInfo = QAction("Info", self.listWidget)
        self.actionMount = QAction("Mount", self.listWidget)
        self.listWidget.addAction(self.actionMount)
        self.listWidget.addAction(self.actionInfo)

        self.actionInfo.triggered.connect(self.showInfo)
        self.actionMount.triggered.connect(self.my_method)
        """
        self.listWidget.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
        self.listWidget.customContextMenuRequested.connect(self.showRightMenu)
        class GuiApplicationLinux(GuiApplicationBase):
            def __init__(self, executable, iconPath, parent=None):
                super(GuiApplicationLinux, self).__init__(iconPath)

                self.eventLoop = 'qt'
                self.app = QApplication(
                    sys.argv)  # this should be done before anything else
                self.executable = executable

                if QIcon.hasThemeIcon(iconPath):
                    icon = QIcon.fromTheme(iconPath)
                else:
                    icon = QIcon(iconPath)

                self.statusIcon = QSystemTrayIcon(icon, parent)
                self.menu = QMenu(parent)

                exitAction = self.menu.addAction("Exit")
                exitAction.triggered.connect(self.quit)

                self.statusIcon.setContextMenu(self.menu)

                def activate(reason):
                    if reason == QSystemTrayIcon.Trigger:
                        return self.launchExecutable()

                QObject.connect(
                    self.statusIcon,
                    SIGNAL("activated(QSystemTrayIcon::ActivationReason)"),
                    activate)

                self.statusIcon.show()

            # A portable icon wrapper. Notify2 demands icon class to be compatible with GdkPixbuf so we
            # provide a compatibility layer
            class IconWrapper(object):
                def __init__(self, iconName):
                    if QIcon.hasThemeIcon(iconName):
                        icon = QIcon.fromTheme(iconName)
                    else:
                        icon = QIcon(iconName)
                    size = icon.availableSizes()[0]
                    self.image = icon.pixmap(size).toImage().convertToFormat(
                        QImage.Format_ARGB32)
                    self.image = self.image.rgbSwapped(
                    )  # otherwise colors are weird :/

                def get_width(self):
                    return self.image.width()

                def get_height(self):
                    return self.image.height()

                def get_rowstride(self):
                    return self.image.bytesPerLine()

                def get_has_alpha(self):
                    return self.image.hasAlphaChannel()

                def get_bits_per_sample(self):
                    return self.image.depth() // self.get_n_channels()

                def get_n_channels(self):
                    if self.image.isGrayscale():
                        return 1
                    elif self.image.hasAlphaChannel():
                        return 4
                    else:
                        return 3

                def get_pixels(self):
                    return self.image.bits().asstring(self.image.numBytes())

            # end of wrapper class

            def getNotificationIcon(self):
                try:
                    return self.IconWrapper(self.iconPath)
                except:
                    logging.error("Failed to get notification icon")
                    return None

            def refreshToolTip(self, players):
                self.statusIcon.setToolTip(self.formTooltip(players))

            def launchExecutable(self, *args):
                try:
                    subprocess.Popen(self.executable, shell=True)
                except:
                    logging.error("Unable to run {0}".format(self.cmd))

            def run(self):
                sys.exit(self.app.exec_())

            def quit(self):
                self.timer.cancel()
                sys.exit(0)
示例#27
0
class LunchinatorGuiController(QObject, LunchServerController):
    _menu = None
    # ---- SIGNALS ----------------
    _initDone = pyqtSignal()
    _performCall = pyqtSignal(object, set, set)
    _sendFile = pyqtSignal(object, bytearray, int, bool)
    _receiveFile = pyqtSignal(object, int, object, int, object, object)
    _processEvent = pyqtSignal(object, object, float, bool, bool)
    _processMessage = pyqtSignal(object, object, float, bool, bool)
    _updateRequested = pyqtSignal()
    _openWindow = pyqtSignal()
    # -----------------------------
    
    def __init__(self): 
        QObject.__init__(self)
        LunchServerController.__init__(self)
        
        getCoreLogger().info("Your PyQt version is %s, based on Qt %s", QtCore.PYQT_VERSION_STR, QtCore.QT_VERSION_STR)
        
        self._shuttingDown = False
        self.resetNextLunchTimeTimer = None
        self._updateAvailable = False
        self._repoUpdates = 0
        self._installUpdatesAction = None
        self._appUpdateStatusAction = None
        self._repoUpdateStatusAction = None
        self._restartAction = None
        self._restartStatusAction = None
        self._restartReason = u""
        self._highlightNewMessage = False
        self._highlightPeersReady = False
        
        self.exitCode = 0
        self.serverThread = None
        self.running = True
        get_server().initialize(self)
        
        self.pluginNameToMenuAction = {}
        
        # initialize main window
        self.mainWindow = LunchinatorWindow(self)
        self.settingsWindow = None
        self.errorDialog = ErrorLogDialog(self.mainWindow)
        self.setParent(self.mainWindow)
        
        if not self.createTrayIcon():
            return
        
        self.mainWindow.createMenuBar(self.pluginActions)
        
        # connect private signals
        self._initDone.connect(self.initDoneSlot)
        self._performCall.connect(self.performCallSlot)
        self._receiveFile.connect(self.receiveFileSlot)
        self._sendFile.connect(self.sendFileSlot)
        
        self._processEvent.connect(self.processEventSlot)
        self._processMessage.connect(self.processMessageSlot)
        self._updateRequested.connect(self.updateRequested)
        self._openWindow.connect(self.openWindowClicked)
        
        get_notification_center().connectApplicationUpdate(self._appUpdateAvailable)
        get_notification_center().connectOutdatedRepositoriesChanged(self._outdatedReposChanged)
        get_notification_center().connectUpdatesDisabled(self._updatesDisabled)
        get_notification_center().connectMessagePrepended(self._newMessage)
        get_notification_center().connectRestartRequired(self._restartRequired)
        get_notification_center().connectPluginActivated(self._pluginActivated)
        get_notification_center().connectPluginDeactivated(self._pluginDeactivated)
        
        self.serverThread = LunchServerThread(self)
        self.serverThread.finished.connect(self.serverFinishedUnexpectedly)
        self.serverThread.finished.connect(self.serverThread.deleteLater)
        self.serverThread.start()
        
    def _initNotificationCenter(self):
        NotificationCenter.setSingletonInstance(NotificationCenterQt(self))
        
    @loggingSlot(time.struct_time, object, object)
    def _newMessage(self, _messageTime, _senderID, _messageText):
        if self.mainWindow.isActiveWindow():
            # dont set highlighted if window is in foreground
            return
        self._highlightNewMessage = True
        self._highlightIcon()
        
    def windowActivated(self):
        """Called from Lunchinator window"""
        if self._highlightNewMessage:
            self._highlightNewMessage = False
            self._highlightIcon()
        
    def _highlightIcon(self):
        if self._highlightNewMessage:
            name = "lunchinatorred"
        elif self._highlightPeersReady:
            name = "lunchinatorgreen"
        else:
            name = "lunchinator"
        
        icon_file = get_settings().get_resource("images", name + (".png" if getPlatform() == PLATFORM_WINDOWS else ".svg"))
        
        icon = None
        if hasattr(QIcon, "fromTheme"):
            icon = QIcon.fromTheme(name, QIcon(icon_file))
        if not icon:
            icon = QIcon(icon_file)
        
        self.statusicon.setIcon(icon)
        
    def createTrayIcon(self):
        if platform.linux_distribution()[0] == "Ubuntu":
            if not os.path.exists('/usr/share/icons/ubuntu-mono-light/status/24/lunchinator.svg') or \
               not os.path.exists('/usr/share/icons/ubuntu-mono-dark/status/24/lunchinator.svg'):
                result = QMessageBox.question(self.mainWindow,
                                              "Install Icons",
                                              "Do you want to install the Lunchinator icons into the Ubuntu theme folders? You will have to enter your sudo password.",
                                              buttons=QMessageBox.Yes | QMessageBox.No,
                                              defaultButton=QMessageBox.Yes)
                if result == QMessageBox.Yes:
                    if subprocess.call(['gksu', get_settings().get_resource('bin', 'install-lunch-icons.sh') + ' lunchinator']) == 0:
                        getCoreLogger().info("restarting after icons were installed")
                        restart(getCoreLogger())
                        return False
                    else:
                        QMessageBox.critical(self.mainWindow,
                                             "Error installing icons",
                                             "The icons were not installed, there was an error.",
                                             buttons=QMessageBox.Ok,
                                             defaultButton=QMessageBox.Ok)
                        getCoreLogger().info("icons were not installed because of an error")
        
        # initialize tray icon
        self.statusicon = QSystemTrayIcon(self.mainWindow)
        # _highlightIcon sets the default icon
        self._highlightIcon()
        contextMenu = self.init_menu(self.mainWindow)
        self.statusicon.activated.connect(self.trayActivated)
        self.statusicon.setContextMenu(contextMenu)
        self.statusicon.show()
        return True
        
    @loggingSlot(QSystemTrayIcon.ActivationReason)
    def trayActivated(self, reason):
        if getPlatform() == PLATFORM_MAC:
            # Trigger is sent even though the context menu is shown.
            return
        if reason == QSystemTrayIcon.Trigger:
            self.statusicon.contextMenu().popup(QCursor.pos())
        
    def _coldShutdown(self, exitCode=0):
        # before exiting, process remaining events (e.g., pending messages like HELO_LEAVE)
        QCoreApplication.processEvents()
        QCoreApplication.exit(exitCode)
        self._shuttingDown = True
        
    def isShuttingDown(self):
        return self._shuttingDown
        
    def quit(self, exitCode=0):
        if self.mainWindow is not None:
            self.mainWindow.close()
        if self.settingsWindow is not None:
            self.settingsWindow.close()
        
        if self.serverThread != None and not sip.isdeleted(self.serverThread) and self.serverThread.isRunning():
            self.serverThread.finished.disconnect(self.serverFinishedUnexpectedly)
            get_server().stop_server()
            getCoreLogger().info("Waiting maximal 30s for server to stop...")
            # wait maximal 30s 
            if self.serverThread.wait(30000):
                getCoreLogger().info("server stopped")
            else:
                getCoreLogger().warning("server not stopped properly")
        else:
            getCoreLogger().info("server not running")
        
        if self.running:
            if get_settings().get_plugins_enabled():
                get_plugin_manager().deactivatePlugins(get_plugin_manager().getAllPlugins(), save_state=False)
                getCoreLogger().info("all plug-ins deactivated")
            if self.mainWindow is not None:
                self.mainWindow.finish()
            if self.settingsWindow is not None:
                self.settingsWindow.finish()
            self.running = False
            
        finalExitCode = 0
        if exitCode != 0:
            finalExitCode = exitCode
        elif self.exitCode != 0:
            finalExitCode = self.exitCode
        else:
            finalExitCode = get_server().exitCode
            
        get_settings().write_config_to_hd()
        DataReceiverThread.cleanup()
            
        self.exitCode = finalExitCode
        
        self._coldShutdown(finalExitCode)
        return finalExitCode
            
    """ ---------------- CALLED FROM LUNCH SERVER -----------------"""
    
    def initDone(self):
        self._initDone.emit()
        
    def call(self, msg, peerIDs, peerIPs):
        self._performCall.emit(msg, peerIDs, peerIPs)
        
    @loggingSlot()
    def serverFinishedUnexpectedly(self):
        self.serverThread = None
        self.quit(EXIT_CODE_ERROR)
        
    def serverStopped(self, exitCode):
        # usually, the emitted signal won't be processed anyway (plug-ins deactivated in quit())
        if exitCode == EXIT_CODE_UPDATE:
            self.serverThread.finished.disconnect(self.serverFinishedUnexpectedly)
            self._updateRequested.emit()    

    def extendMemberInfo(self, infoDict):
        super(LunchinatorGuiController, self).extendMemberInfo(infoDict)
        infoDict['pyqt_version'] = QtCore.PYQT_VERSION_STR
        infoDict['qt_version'] = QtCore.QT_VERSION_STR
            
    def getOpenPort(self, ip):
        return DataReceiverThread.getOpenPort(category="avatar%s" % ip)
        
    def receiveFile(self, ip, fileSize, fileName, tcp_port, successFunc=None, errorFunc=None):
        self._receiveFile.emit(ip, fileSize, fileName, tcp_port, successFunc, errorFunc)
    
    def sendFile(self, ip, fileOrData, otherTCPPort, isData=False):
        if not isData and type(fileOrData) == unicode:
            # encode to send as str
            fileOrData = fileOrData.encode('utf-8')
        self._sendFile.emit(ip, bytearray(fileOrData), otherTCPPort, isData)

    def processEvent(self, xmsg, addr, eventTime, newPeer, fromQueue):
        """ process any non-message event 
        @type xmsg: extMessageIncoming
        @type addr: unicode
        @type eventTime: float
        @type newPeer: bool
        @type fromQueue: bool
        """
        self._processEvent.emit(xmsg, addr, eventTime, newPeer, fromQueue)
    
    
    def processMessage(self, xmsg, addr, eventTime, newPeer, fromQueue):
        """ process any message event, including lunch calls 
        @type cmd: unicode
        @type xmsg: extMessageIncoming
        @type addr: unicode
        @type eventTime: float
        @type newPeer: bool
        @type fromQueue: bool
        """
        self._processMessage.emit(xmsg, addr, eventTime, newPeer, fromQueue)
    
    def getMainGUI(self):
        return self.mainWindow
    """ ----------------- CALLED ON MAIN THREAD -------------------"""
    
    def _updateRepoUpdateStatusAction(self):
        status = ""
        if self._repoUpdates == 1:
            status = "1 plugin repository can be updated"
        elif self._repoUpdates > 1:
            status = "%d plugin repositories can be updated" % self._repoUpdates
        self._repoUpdateStatusAction.setText(status)
            
        self._repoUpdateStatusAction.setVisible(self._repoUpdates > 0)
    
    @loggingSlot()
    def _appUpdateAvailable(self):
        self._updateAvailable = True
        if self._appUpdateStatusAction != None:
            self._appUpdateStatusAction.setVisible(True)
        self.notifyUpdates()
    
    @loggingSlot()
    def _outdatedReposChanged(self):
        self._repoUpdates = get_settings().get_plugin_repositories().getNumOutdated()
        if self._repoUpdateStatusAction != None:
            self._updateRepoUpdateStatusAction()
        self.notifyUpdates()
        
    @loggingSlot()
    def _updatesDisabled(self):
        if self._repoUpdateStatusAction != None:
            self._repoUpdateStatusAction.setVisible(False)
        if self._appUpdateStatusAction != None:
            self._appUpdateStatusAction.setVisible(False)
        if self._installUpdatesAction != None:
            self._installUpdatesAction.setVisible(False)
        self._updateAvailable = False
        
    def _hasUpdates(self):
        return self._updateAvailable or self._repoUpdates > 0
        
    @loggingSlot(object)
    def _restartRequired(self, reason):
        reason = convert_string(reason)
        if self._restartReason == reason:
            # same reason again, do not notify
            return
        
        displayNotification(u"Restart required", reason, getCoreLogger())
        
        if self._restartReason:
            # now there are multiple reasons to restart
            self._restartReason = u"Some changes need a restart"
        else:
            self._restartReason = reason
        if self._restartStatusAction != None:
            self._restartStatusAction.setText(self._restartReason)
            self._restartStatusAction.setVisible(True)
            # don't need both actions
            if not self._hasUpdates():
                self._restartAction.setVisible(True)
    
    def notifyUpdates(self):
        hasUpdates = self._hasUpdates()
        if self._installUpdatesAction != None:
            self._installUpdatesAction.setVisible(hasUpdates)
            # don't need both
            self._restartAction.setVisible(False)
    
    def _getDisplayedName(self, pluginInfo):
        return pluginInfo.plugin_object.get_displayed_name() if pluginInfo.plugin_object.get_displayed_name() else pluginInfo.name
    
    def _create_plugin_action(self, pluginInfo, parentMenu, aCat):
        displayedName = self._getDisplayedName(pluginInfo) 
        anAction = parentMenu.addAction(displayedName)
        anAction.setCheckable(True)
        anAction.setChecked(pluginInfo.plugin_object.is_activated)
        anAction.triggered.connect(partial(self.toggle_plugin, pluginInfo.name, aCat), type=Qt.DirectConnection)
        self.pluginNameToMenuAction[pluginInfo.name] = anAction
        return anAction
        
    def init_menu(self, parent):        
        # create the plugin submenu
        menu = QMenu(parent)
        plugin_menu = QMenu("PlugIns", menu)
        
        self.pluginActions = None
        if get_settings().get_plugins_enabled():
            allPlugins = [x for x in get_plugin_manager().getAllPlugins() if not x.plugin_object.is_activation_forced()]
            
            if get_settings().get_group_plugins():
                self.pluginActions = {}
                catMenus = {}
                
                for pluginInfo in sorted(allPlugins, key=lambda info : self._getDisplayedName(info)):                
                    categoryMenu = None
                    anAction = None
                    for aCat in pluginInfo.categories:
                        if aCat in catMenus:
                            categoryMenu = catMenus[aCat]
                        else:
                            categoryMenu = QMenu(aCat, plugin_menu)
                            catMenus[aCat] = categoryMenu
                    
                        if anAction == None:
                            anAction = self._create_plugin_action(pluginInfo, categoryMenu, aCat)
                        else:
                            categoryMenu.addAction(anAction)
                        
                        if aCat in self.pluginActions:
                            self.pluginActions[aCat].append(anAction)
                        else:
                            self.pluginActions[aCat] = [anAction]
                for _cat, aMenu in sorted(catMenus.iteritems(), key=lambda aTuple : aTuple[0]):
                    plugin_menu.addMenu(aMenu)
            else:
                self.pluginActions = []
                for pluginInfo in sorted(allPlugins, key=lambda info : self._getDisplayedName(info)):
                    anAction = self._create_plugin_action(pluginInfo, plugin_menu, pluginInfo.categories[0])
                    self.pluginActions.append(anAction)
        
        # main _menu
        self._memberStatusAction = menu.addAction("Initializing...")
        self._memberStatusAction.setEnabled(False)
        
        if hasattr(menu, "addSeparator"):
            menu.addSeparator()
            
        get_notification_center().connectMemberAppended(self._updateMemberStatus)
        get_notification_center().connectMemberUpdated(self._updateMemberStatus)
        get_notification_center().connectMemberRemoved(self._updateMemberStatus)
        self.memberStatusUpdateTimer = QTimer(self)
        self.memberStatusUpdateTimer.timeout.connect(self._startSyncedTimer)
        self.memberStatusUpdateTimer.start(msecUntilNextMinute())
        
        anAction = menu.addAction('Call for lunch')
        anAction.triggered.connect(partial(self.sendMessageClicked, u'lunch'))
        
        anAction = menu.addAction('Show Lunchinator')
        anAction.triggered.connect(self.openWindowClicked)
        
        anAction = menu.addAction(u"Change today's lunch time")
        anAction.triggered.connect(self.changeNextLunchTime)
        
        if hasattr(menu, "addSeparator"):
            menu.addSeparator()
        
        anAction = menu.addAction('Settings')
        anAction.triggered.connect(self.openSettingsClicked)
        
        menu.addMenu(plugin_menu)
        
        if hasattr(menu, "addSeparator"):
            menu.addSeparator()
        
        self._restartStatusAction = menu.addAction(self._restartReason)
        self._restartStatusAction.setEnabled(False)
        self._restartAction = menu.addAction("Restart")
        self._restartAction.triggered.connect(partial(restart, getCoreLogger()))
        if self._restartReason:
            self._restartStatusAction.setVisible(True)
            self._restartAction.setVisible(True)
        else:
            self._restartStatusAction.setVisible(False)
            self._restartAction.setVisible(False)
        
        self._appUpdateStatusAction = menu.addAction("Lunchinator can be updated")
        self._appUpdateStatusAction.setEnabled(False)
        self._appUpdateStatusAction.setVisible(self._updateAvailable)
        
        self._repoUpdateStatusAction = menu.addAction("")
        self._repoUpdateStatusAction.setEnabled(False)
        self._updateRepoUpdateStatusAction()
        
        self._installUpdatesAction = menu.addAction("Install updates and restart")
        self._installUpdatesAction.triggered.connect(get_notification_center().emitInstallUpdates)
        self._installUpdatesAction.setVisible(self._updateAvailable)
        
        anAction = menu.addAction('Exit')
        anAction.triggered.connect(self.quitClicked)
            
        return menu
    
    @loggingSlot()
    def _startSyncedTimer(self):
        self._updateMemberStatus()
        self.memberStatusUpdateTimer.timeout.disconnect(self._startSyncedTimer)
        self.memberStatusUpdateTimer.timeout.connect(self._updateMemberStatus)
        self.memberStatusUpdateTimer.start(60000)
    
    @pyqtSlot()
    @pyqtSlot(object)
    @loggingSlot(object, object)
    def _updateMemberStatus(self, _pID=None, _pInfo=None):
        peers = get_server().getLunchPeers()
        readyMembers = peers.getReadyMembers()
        notReadyMembers = peers.getMembers() - readyMembers
        
        # don't display members with unknown status as ready
        readyMembers = [pID for pID in readyMembers if peers.isPeerReadinessKnown(pID=pID)]
        
        everybodyReady = False
        if not readyMembers and not notReadyMembers:
            status = u"No members."
        elif not readyMembers:
            status = u"Nobody is ready for lunch."
        elif not notReadyMembers:
            everybodyReady = True
            status = u"Everybody is ready for lunch."
        else:
            if len(readyMembers) == 1:
                ready = u"1 member"
            else:
                ready = u"%d members" % len(readyMembers)
                
            if len(notReadyMembers) == 1:
                notReady = u"1 member"
            else:
                notReady = u"%d members" % len(notReadyMembers)
            
            status = u"%s ready, %s not ready for lunch." % (ready, notReady)
        if everybodyReady and not self._highlightPeersReady:
            # don't highlight if I am the only member
            if len(readyMembers) > 1 or not get_peers().isMe(pID=iter(readyMembers).next()):
                self._highlightPeersReady = True
                if get_settings().get_notification_if_everybody_ready():
                    displayNotification("Lunch Time",
                                        "Everybody is ready for lunch now",
                                        getCoreLogger(),
                                        get_settings().get_resource("images", "lunchinator.png"))
                self._highlightIcon()
            else:
                status = u"You are the only member."
        elif not everybodyReady and self._highlightPeersReady:
            self._highlightPeersReady = False
            self._highlightIcon()
        self._memberStatusAction.setText(status)
    
    def disable_auto_update(self):
        get_settings().set_auto_update_enabled(False)
                  
    def _insertMessage(self, mtime, addr, msg):
        QCoreApplication.processEvents()
        LunchServerController._insertMessage(self, mtime, addr, msg)
                  
    """---------------------- SLOTS ------------------------------"""
    
    @loggingSlot()
    def initDoneSlot(self):
        pass
    
    @loggingSlot(object, set, set)
    def performCallSlot(self, msg, peerIDs, peerIPs):
        get_server().perform_call(msg, peerIDs, peerIPs)
    
    @loggingSlot()
    def updateRequested(self):
        self.quit(EXIT_CODE_UPDATE)
    
    @loggingSlot(object, object)
    def _pluginActivated(self, pluginName, _category):
        pluginName = convert_string(pluginName)
        if pluginName in self.pluginNameToMenuAction:
            anAction = self.pluginNameToMenuAction[pluginName]
            anAction.setChecked(True)
            
    @loggingSlot(object, object)
    def _pluginDeactivated(self, pluginName, _category):
        pluginName = convert_string(pluginName)
        if pluginName in self.pluginNameToMenuAction:
            anAction = self.pluginNameToMenuAction[pluginName]
            anAction.setChecked(False)

    @loggingSlot(object, object, bool)
    def toggle_plugin(self, p_name, p_cat, new_state):
        try:
            p_cat = convert_string(p_cat)
            p_name = convert_string(p_name)
            
            if new_state:
                get_plugin_manager().activatePluginByName(p_name, p_cat)
            else:
                get_plugin_manager().deactivatePluginByName(p_name, p_cat)
        except:
            getCoreLogger().exception("Error toggling plugin")
    
    @loggingSlot(object, QObject)
    def sendMessageClicked(self, message, text):
        if message != None:
            get_server().call_all_members(convert_string(message))
        else:
            get_server().call_all_members(text)
        
    @loggingSlot(QLineEdit)
    def addHostClicked(self, hostn):
        try:
            ip = socket.gethostbyname(hostn.strip())
            get_server().call_request_info([ip])
        except:
            d = QMessageBox(QMessageBox.Critical, "Error adding host", "Cannot add host: Hostname unknown: %s" % hostn, QMessageBox.Ok, self.mainWindow)
            d.exec_()
            
    @pyqtSlot(bool)
    @loggingSlot()
    def quitClicked(self, _=None):
        self.quit()

    @pyqtSlot(bool)
    @loggingSlot()
    def openWindowClicked(self, _=None):    
        if self.mainWindow == None:
            getCoreLogger().error("mainWindow is not initialized")
            return
        self.mainWindow.showNormal()
        self.mainWindow.raise_()
        self.mainWindow.activateWindow()
            
    @loggingSlot()
    def changeNextLunchTime(self, begin = None, end = None):
        if begin == None:
            if self.mainWindow == None:
                getCoreLogger().error("mainWindow is not initialized")
                return
            from lunchinator.timespan_input_dialog import TimespanInputDialog
            dialog = TimespanInputDialog(self.mainWindow, "Change Lunch Time", "When are you free for lunch today?", get_settings().get_next_lunch_begin(), get_settings().get_next_lunch_end())
            dialog.exec_()
            if dialog.result() == QDialog.Accepted:
                get_settings().set_next_lunch_time(dialog.getBeginTimeString(), dialog.getEndTimeString())
            else:
                return        
        else:
            get_settings().set_next_lunch_time(begin, end) 
            
        if self.resetNextLunchTimeTimer != None:
            self.resetNextLunchTimeTimer.stop()
            self.resetNextLunchTimeTimer.deleteLater()
            
        td = get_settings().get_next_lunch_reset_time()
        if td > 0:
            self.resetNextLunchTimeTimer = QTimer(getValidQtParent())
            self.resetNextLunchTimeTimer.timeout.connect(self._resetNextLunchTime)
            self.resetNextLunchTimeTimer.setSingleShot(True)
            self.resetNextLunchTimeTimer.start(abs(td) + 1000)
            
        get_server().call_info()
            
    @loggingSlot()
    def _resetNextLunchTime(self):
        get_settings().set_next_lunch_time(None, None)
        get_server().call_info()
            
    @pyqtSlot(bool)
    @loggingSlot()
    def openSettingsClicked(self, _=None):
        if self.mainWindow == None:
            getCoreLogger().error("mainWindow not specified")
            return
        
        if self.settingsWindow == None:
            self.settingsWindow = LunchinatorSettingsDialog(self.mainWindow)
            self.settingsWindow.save.connect(partial(self.settingsDialogAction, True))
            self.settingsWindow.discard.connect(partial(self.settingsDialogAction, False))

        self.settingsWindow.showNormal()
        self.settingsWindow.raise_()
        self.settingsWindow.activateWindow()

    @loggingSlot()        
    def settingsDialogAction(self, saved):
        if not get_settings().get_plugins_enabled():
            return
        for pluginInfo in get_plugin_manager().getAllPlugins():
            if pluginInfo.plugin_object.is_activated and self.settingsWindow.isOptionsWidgetLoaded(pluginInfo.name):
                if saved:
                    try:
                        pluginInfo.plugin_object.save_options_widget_data(sendInfoDict=False)
                    except:
                        getCoreLogger().exception("was not able to save data for plugin %s", pluginInfo.name)
                else:
                    pluginInfo.plugin_object.discard_changes()
        get_settings().write_config_to_hd()
            
        get_server().call_info()      

    @loggingSlot(object, bytearray, int, bool)
    def sendFileSlot(self, addr, fileToSend, other_tcp_port, isData):
        addr = convert_string(addr)
        if isData:
            fileToSend = str(fileToSend)
            ds = DataSenderThread.sendData(addr, other_tcp_port, fileToSend, getCoreLogger(), parent=self)
        else:
            fileToSend = str(fileToSend).decode("utf-8")
            ds = DataSenderThread.sendSingleFile(addr, other_tcp_port, fileToSend, getCoreLogger(), parent=self)
        ds.finished.connect(ds.deleteLater)
        ds.start()
        
    @loggingSlot(QThread, object)
    def successfullyReceivedFile(self, _thread, filePath):
        getCoreLogger().info("successfully received file %s", filePath)
        
    @loggingSlot(QThread, object)
    def errorOnTransfer(self, _thread, message):
        getCoreLogger().warning("Error receiving file (%s)", message)
    
    @loggingSlot(object, int, object, int, object, object)
    def receiveFileSlot(self, addr, file_size, file_name, tcp_port, successFunc, errorFunc):
        addr = convert_string(addr)
        file_name = convert_string(file_name)
        dr = DataReceiverThread.receiveSingleFile(addr, file_name, file_size, tcp_port, getCoreLogger(), "avatar%s" % addr, True, parent=self)
        if successFunc:
            dr.successfullyTransferred.connect(lambda _thread, _path : successFunc())
        if errorFunc:
            dr.errorOnTransfer.connect(lambda _thread, _msg : errorFunc())
        dr.successfullyTransferred.connect(self.successfullyReceivedFile)
        dr.errorOnTransfer.connect(self.errorOnTransfer)
        dr.finished.connect(dr.deleteLater)
        dr.start()
        
    @loggingSlot(object, object, float, bool, bool)
    def processEventSlot(self, xmsg, addr, eventTime, newPeer, fromQueue):
        """ process events that are not group messages
        @type xmsg: extendedMessageIncoming
        @type addr: unicode
        @type eventTime: float
        @type newPeer: bool
        @type fromQueue: bool
        """
        super(LunchinatorGuiController, self).processEvent(xmsg, addr, eventTime, newPeer, fromQueue)
     
    @loggingSlot(object, object, float, bool, bool)
    def processMessageSlot(self, xmsg, addr, eventTime, newPeer, fromQueue):
        """ process any message event, including lunch calls
        @type xmsg: extendedMessageIncoming
        @type addr: unicode
        @type eventTime: float
        @type newPeer: bool
        @type fromQueue: bool
        """

        super(LunchinatorGuiController, self).processMessage(xmsg, addr, eventTime, newPeer, fromQueue)
示例#28
0
class MainWindow(base_class, ui_class):
    implements(IObserver)

    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.saved_account_state = None

        notification_center = NotificationCenter()
        notification_center.add_observer(self, name='SIPApplicationWillStart')
        notification_center.add_observer(self, name='SIPApplicationDidStart')
        notification_center.add_observer(self, name='SIPAccountGotMessageSummary')
        notification_center.add_observer(self, name='SIPAccountGotPendingWatcher')
        notification_center.add_observer(self, name='BlinkSessionNewOutgoing')
        notification_center.add_observer(self, name='BlinkSessionDidReinitializeForOutgoing')
        notification_center.add_observer(self, name='FileTransferNewIncoming')
        notification_center.add_observer(self, name='FileTransferNewOutgoing')
        notification_center.add_observer(self, sender=AccountManager())

        icon_manager = IconManager()

        self.pending_watcher_dialogs = []

        self.mwi_icons = [QIcon(Resources.get('icons/mwi-%d.png' % i)) for i in xrange(0, 11)]
        self.mwi_icons.append(QIcon(Resources.get('icons/mwi-many.png')))

        with Resources.directory:
            self.setupUi()

        self.setWindowTitle('Blink')
        self.setWindowIconText('Blink')

        geometry = QSettings().value("main_window/geometry")
        if geometry:
            self.restoreGeometry(geometry)

        self.default_icon_path = Resources.get('icons/default-avatar.png')
        self.default_icon = QIcon(self.default_icon_path)
        self.last_icon_directory = Path('~').normalized
        self.set_user_icon(icon_manager.get('avatar'))

        self.active_sessions_label.hide()
        self.enable_call_buttons(False)
        self.conference_button.setEnabled(False)
        self.hangup_all_button.setEnabled(False)
        self.sip_server_settings_action.setEnabled(False)
        self.search_for_people_action.setEnabled(False)
        self.history_on_server_action.setEnabled(False)
        self.main_view.setCurrentWidget(self.contacts_panel)
        self.contacts_view.setCurrentWidget(self.contact_list_panel)
        self.search_view.setCurrentWidget(self.search_list_panel)

        # System tray
        if QSystemTrayIcon.isSystemTrayAvailable() and not os.getenv('XDG_CURRENT_DESKTOP', '').lower().startswith('unity'):
            self.system_tray_icon = QSystemTrayIcon(QIcon(Resources.get('icons/blink.png')), self)
            self.system_tray_icon.activated.connect(self._SH_SystemTrayIconActivated)
            menu = QMenu(self)
            menu.addAction(QAction("Show", self, triggered=self._AH_SystemTrayShowWindow))
            menu.addAction(QAction(QIcon(Resources.get('icons/application-exit.png')), "Quit", self, triggered=self._AH_QuitActionTriggered))
            self.system_tray_icon.setContextMenu(menu)
            self.system_tray_icon.show()
        else:
            self.system_tray_icon = None

        # Accounts
        self.account_model = AccountModel(self)
        self.enabled_account_model = ActiveAccountModel(self.account_model, self)
        self.server_tools_account_model = ServerToolsAccountModel(self.account_model, self)
        self.identity.setModel(self.enabled_account_model)

        # Contacts
        self.contact_model = ContactModel(self)
        self.contact_search_model = ContactSearchModel(self.contact_model, self)
        self.contact_list.setModel(self.contact_model)
        self.search_list.setModel(self.contact_search_model)

        # Sessions (audio)
        self.session_model = AudioSessionModel(self)
        self.session_list.setModel(self.session_model)
        self.session_list.selectionModel().selectionChanged.connect(self._SH_SessionListSelectionChanged)

        # History
        self.history_manager = HistoryManager()

        # Windows, dialogs and panels
        self.about_panel = AboutPanel(self)
        self.conference_dialog = ConferenceDialog(self)
        self.contact_editor_dialog = ContactEditorDialog(self)
        self.google_contacts_dialog = GoogleContactsDialog(self)
        self.filetransfer_window = FileTransferWindow()
        self.preferences_window = PreferencesWindow(self.account_model, None)
        self.server_tools_window = ServerToolsWindow(self.server_tools_account_model, None)

        # Signals
        self.account_state.stateChanged.connect(self._SH_AccountStateChanged)
        self.account_state.clicked.connect(self._SH_AccountStateClicked)
        self.activity_note.editingFinished.connect(self._SH_ActivityNoteEditingFinished)
        self.add_contact_button.clicked.connect(self._SH_AddContactButtonClicked)
        self.add_search_contact_button.clicked.connect(self._SH_AddContactButtonClicked)
        self.audio_call_button.clicked.connect(self._SH_AudioCallButtonClicked)
        self.video_call_button.clicked.connect(self._SH_VideoCallButtonClicked)
        self.chat_session_button.clicked.connect(self._SH_ChatSessionButtonClicked)
        self.back_to_contacts_button.clicked.connect(self.search_box.clear) # this can be set in designer -Dan
        self.conference_button.makeConference.connect(self._SH_MakeConference)
        self.conference_button.breakConference.connect(self._SH_BreakConference)

        self.contact_list.selectionModel().selectionChanged.connect(self._SH_ContactListSelectionChanged)
        self.contact_model.itemsAdded.connect(self._SH_ContactModelAddedItems)
        self.contact_model.itemsRemoved.connect(self._SH_ContactModelRemovedItems)

        self.display_name.editingFinished.connect(self._SH_DisplayNameEditingFinished)
        self.hangup_all_button.clicked.connect(self._SH_HangupAllButtonClicked)

        self.identity.activated[int].connect(self._SH_IdentityChanged)
        self.identity.currentIndexChanged[int].connect(self._SH_IdentityCurrentIndexChanged)

        self.mute_button.clicked.connect(self._SH_MuteButtonClicked)

        self.search_box.textChanged.connect(self._SH_SearchBoxTextChanged)
        self.search_box.returnPressed.connect(self._SH_SearchBoxReturnPressed)
        self.search_box.shortcut.activated.connect(self.search_box.setFocus)

        self.search_list.selectionModel().selectionChanged.connect(self._SH_SearchListSelectionChanged)

        self.server_tools_account_model.rowsInserted.connect(self._SH_ServerToolsAccountModelChanged)
        self.server_tools_account_model.rowsRemoved.connect(self._SH_ServerToolsAccountModelChanged)

        self.session_model.sessionAdded.connect(self._SH_AudioSessionModelAddedSession)
        self.session_model.sessionRemoved.connect(self._SH_AudioSessionModelRemovedSession)
        self.session_model.structureChanged.connect(self._SH_AudioSessionModelChangedStructure)

        self.silent_button.clicked.connect(self._SH_SilentButtonClicked)
        self.switch_view_button.viewChanged.connect(self._SH_SwitchViewButtonChangedView)

        # Blink menu actions
        self.about_action.triggered.connect(self.about_panel.show)
        self.add_account_action.triggered.connect(self.preferences_window.show_add_account_dialog)
        self.manage_accounts_action.triggered.connect(self.preferences_window.show_for_accounts)
        self.help_action.triggered.connect(partial(QDesktopServices.openUrl, QUrl(u'http://icanblink.com/help-qt.phtml')))
        self.preferences_action.triggered.connect(self.preferences_window.show)
        self.auto_accept_chat_action.triggered.connect(self._AH_AutoAcceptChatActionTriggered)
        self.received_messages_sound_action.triggered.connect(self._AH_ReceivedMessagesSoundActionTriggered)
        self.answering_machine_action.triggered.connect(self._AH_EnableAnsweringMachineActionTriggered)
        self.release_notes_action.triggered.connect(partial(QDesktopServices.openUrl, QUrl(u'http://icanblink.com/changelog-qt.phtml')))
        self.quit_action.triggered.connect(self._AH_QuitActionTriggered)

        # Call menu actions
        self.redial_action.triggered.connect(self._AH_RedialActionTriggered)
        self.join_conference_action.triggered.connect(self.conference_dialog.show)
        self.history_menu.aboutToShow.connect(self._SH_HistoryMenuAboutToShow)
        self.history_menu.triggered.connect(self._AH_HistoryMenuTriggered)
        self.output_devices_group.triggered.connect(self._AH_AudioOutputDeviceChanged)
        self.input_devices_group.triggered.connect(self._AH_AudioInputDeviceChanged)
        self.alert_devices_group.triggered.connect(self._AH_AudioAlertDeviceChanged)
        self.video_devices_group.triggered.connect(self._AH_VideoDeviceChanged)
        self.mute_action.triggered.connect(self._SH_MuteButtonClicked)
        self.silent_action.triggered.connect(self._SH_SilentButtonClicked)

        # Tools menu actions
        self.sip_server_settings_action.triggered.connect(self._AH_SIPServerSettings)
        self.search_for_people_action.triggered.connect(self._AH_SearchForPeople)
        self.history_on_server_action.triggered.connect(self._AH_HistoryOnServer)

        # Window menu actions
        self.chat_window_action.triggered.connect(self._AH_ChatWindowActionTriggered)
        self.transfers_window_action.triggered.connect(self._AH_TransfersWindowActionTriggered)
        self.logs_window_action.triggered.connect(self._AH_LogsWindowActionTriggered)
        self.received_files_window_action.triggered.connect(self._AH_ReceivedFilesWindowActionTriggered)
        self.screenshots_window_action.triggered.connect(self._AH_ScreenshotsWindowActionTriggered)

    def setupUi(self):
        super(MainWindow, self).setupUi(self)

        self.search_box.shortcut = QShortcut(self.search_box)
        self.search_box.shortcut.setKey('Ctrl+F')

        self.output_devices_group = QActionGroup(self)
        self.input_devices_group = QActionGroup(self)
        self.alert_devices_group = QActionGroup(self)
        self.video_devices_group = QActionGroup(self)

        self.request_screen_action = QAction('Request screen', self, triggered=self._AH_RequestScreenActionTriggered)
        self.share_my_screen_action = QAction('Share my screen', self, triggered=self._AH_ShareMyScreenActionTriggered)
        self.screen_sharing_button.addAction(self.request_screen_action)
        self.screen_sharing_button.addAction(self.share_my_screen_action)

        # adjust search box height depending on theme as the value set in designer isn't suited for all themes
        search_box = self.search_box
        option = QStyleOptionFrameV2()
        search_box.initStyleOption(option)
        frame_width = search_box.style().pixelMetric(QStyle.PM_DefaultFrameWidth, option, search_box)
        if frame_width < 4:
            search_box.setMinimumHeight(20 + 2*frame_width)

        # adjust the combo boxes for themes with too much padding (like the default theme on Ubuntu 10.04)
        option = QStyleOptionComboBox()
        self.identity.initStyleOption(option)
        wide_padding = self.identity.style().subControlRect(QStyle.CC_ComboBox, option, QStyle.SC_ComboBoxEditField, self.identity).height() < 10
        self.identity.setStyleSheet("""QComboBox { padding: 0px 4px 0px 4px; }""" if wide_padding else "")

    def closeEvent(self, event):
        QSettings().setValue("main_window/geometry", self.saveGeometry())
        super(MainWindow, self).closeEvent(event)
        self.about_panel.close()
        self.contact_editor_dialog.close()
        self.google_contacts_dialog.close()
        self.server_tools_window.close()
        for dialog in self.pending_watcher_dialogs[:]:
            dialog.close()

    def show(self):
        super(MainWindow, self).show()
        self.raise_()
        self.activateWindow()

    def set_user_icon(self, icon):
        self.account_state.setIcon(icon or self.default_icon)

    def enable_call_buttons(self, enabled):
        self.audio_call_button.setEnabled(enabled)
        self.video_call_button.setEnabled(enabled)
        self.chat_session_button.setEnabled(enabled)
        self.screen_sharing_button.setEnabled(enabled)

    def load_audio_devices(self):
        settings = SIPSimpleSettings()

        action = QAction(u'System default', self.output_devices_group)
        action.setData(u'system_default')
        self.output_device_menu.addAction(action)
        self.output_device_menu.addSeparator()
        for device in SIPApplication.engine.output_devices:
            action = QAction(device, self.output_devices_group)
            action.setData(device)
            self.output_device_menu.addAction(action)
        action = QAction(u'None', self.output_devices_group)
        action.setData(None)
        self.output_device_menu.addAction(action)
        for action in self.output_devices_group.actions():
            action.setCheckable(True)
            if settings.audio.output_device == action.data():
                action.setChecked(True)

        action = QAction(u'System default', self.input_devices_group)
        action.setData(u'system_default')
        self.input_device_menu.addAction(action)
        self.input_device_menu.addSeparator()
        for device in SIPApplication.engine.input_devices:
            action = QAction(device, self.input_devices_group)
            action.setData(device)
            self.input_device_menu.addAction(action)
        action = QAction(u'None', self.input_devices_group)
        action.setData(None)
        self.input_device_menu.addAction(action)
        for action in self.input_devices_group.actions():
            action.setCheckable(True)
            if settings.audio.input_device == action.data():
                action.setChecked(True)

        action = QAction(u'System default', self.alert_devices_group)
        action.setData(u'system_default')
        self.alert_device_menu.addAction(action)
        self.alert_device_menu.addSeparator()
        for device in SIPApplication.engine.output_devices:
            action = QAction(device, self.alert_devices_group)
            action.setData(device)
            self.alert_device_menu.addAction(action)
        action = QAction(u'None', self.alert_devices_group)
        action.setData(None)
        self.alert_device_menu.addAction(action)
        for action in self.alert_devices_group.actions():
            action.setCheckable(True)
            if settings.audio.alert_device == action.data():
                action.setChecked(True)

    def load_video_devices(self):
        settings = SIPSimpleSettings()

        action = QAction(u'System default', self.video_devices_group)
        action.setData(u'system_default')
        self.video_camera_menu.addAction(action)
        self.video_camera_menu.addSeparator()
        for device in SIPApplication.engine.video_devices:
            action = QAction(device, self.video_devices_group)
            action.setData(device)
            self.video_camera_menu.addAction(action)
        action = QAction(u'None', self.video_devices_group)
        action.setData(None)
        self.video_camera_menu.addAction(action)
        for action in self.video_devices_group.actions():
            action.setCheckable(True)
            if settings.video.device == action.data():
                action.setChecked(True)

    def _AH_AccountActionTriggered(self, action, enabled):
        account = action.data()
        account.enabled = enabled
        account.save()

    def _AH_AudioAlertDeviceChanged(self, action):
        settings = SIPSimpleSettings()
        settings.audio.alert_device = action.data()
        settings.save()

    def _AH_AudioInputDeviceChanged(self, action):
        settings = SIPSimpleSettings()
        settings.audio.input_device = action.data()
        settings.save()

    def _AH_AudioOutputDeviceChanged(self, action):
        settings = SIPSimpleSettings()
        settings.audio.output_device = action.data()
        settings.save()

    def _AH_VideoDeviceChanged(self, action):
        settings = SIPSimpleSettings()
        settings.video.device = action.data()
        settings.save()

    def _AH_AutoAcceptChatActionTriggered(self, checked):
        settings = SIPSimpleSettings()
        settings.chat.auto_accept = checked
        settings.save()

    def _AH_ReceivedMessagesSoundActionTriggered(self, checked):
        settings = SIPSimpleSettings()
        settings.sounds.play_message_alerts = checked
        settings.save()

    def _AH_EnableAnsweringMachineActionTriggered(self, checked):
        settings = SIPSimpleSettings()
        settings.answering_machine.enabled = checked
        settings.save()

    def _AH_GoogleContactsActionTriggered(self):
        settings = SIPSimpleSettings()
        if settings.google_contacts.authorization_token is not None:
            settings.google_contacts.authorization_token = None
            settings.save()
            self.google_contacts_dialog.hide()
        else:
            self.google_contacts_dialog.open()

    def _AH_RedialActionTriggered(self):
        session_manager = SessionManager()
        if session_manager.last_dialed_uri is not None:
            contact, contact_uri = URIUtils.find_contact(session_manager.last_dialed_uri)
            session_manager.create_session(contact, contact_uri, [StreamDescription('audio')]) # TODO: remember used media types and redial with them. -Saul

    def _AH_SIPServerSettings(self, checked):
        account = self.identity.itemData(self.identity.currentIndex()).account
        account = account if account is not BonjourAccount() and account.server.settings_url else None
        self.server_tools_window.open_settings_page(account)

    def _AH_SearchForPeople(self, checked):
        account = self.identity.itemData(self.identity.currentIndex()).account
        account = account if account is not BonjourAccount() and account.server.settings_url else None
        self.server_tools_window.open_search_for_people_page(account)

    def _AH_HistoryOnServer(self, checked):
        account = self.identity.itemData(self.identity.currentIndex()).account
        account = account if account is not BonjourAccount() and account.server.settings_url else None
        self.server_tools_window.open_history_page(account)

    def _AH_ChatWindowActionTriggered(self, checked):
        blink = QApplication.instance()
        blink.chat_window.show()

    def _AH_TransfersWindowActionTriggered(self, checked):
        self.filetransfer_window.show()

    def _AH_LogsWindowActionTriggered(self, checked):
        directory = ApplicationData.get('logs')
        makedirs(directory)
        QDesktopServices.openUrl(QUrl.fromLocalFile(directory))

    def _AH_ReceivedFilesWindowActionTriggered(self, checked):
        settings = SIPSimpleSettings()
        directory = settings.file_transfer.directory.normalized
        makedirs(directory)
        QDesktopServices.openUrl(QUrl.fromLocalFile(directory))

    def _AH_ScreenshotsWindowActionTriggered(self, checked):
        settings = BlinkSettings()
        directory = settings.screen_sharing.screenshots_directory.normalized
        makedirs(directory)
        QDesktopServices.openUrl(QUrl.fromLocalFile(directory))

    def _AH_VoicemailActionTriggered(self, action, checked):
        account = action.data()
        contact, contact_uri = URIUtils.find_contact(account.voicemail_uri, display_name='Voicemail')
        session_manager = SessionManager()
        session_manager.create_session(contact, contact_uri, [StreamDescription('audio')], account=account)

    def _SH_HistoryMenuAboutToShow(self):
        self.history_menu.clear()
        if self.history_manager.calls:
            for entry in reversed(self.history_manager.calls):
                action = self.history_menu.addAction(entry.icon, entry.text)
                action.entry = entry
                action.setToolTip(entry.uri)
        else:
            action = self.history_menu.addAction("Call history is empty")
            action.setEnabled(False)

    def _AH_HistoryMenuTriggered(self, action):
        account_manager = AccountManager()
        session_manager = SessionManager()
        try:
            account = account_manager.get_account(action.entry.account_id)
        except KeyError:
            account = None
        contact, contact_uri = URIUtils.find_contact(action.entry.uri)
        session_manager.create_session(contact, contact_uri, [StreamDescription('audio')], account=account) # TODO: memorize media type and use it? -Saul (not sure about history in/out -Dan)

    def _AH_SystemTrayShowWindow(self, checked):
        self.show()
        self.raise_()
        self.activateWindow()

    def _AH_QuitActionTriggered(self, checked):
        if self.system_tray_icon is not None:
            self.system_tray_icon.hide()
        QApplication.instance().quit()

    def _SH_AccountStateChanged(self):
        self.activity_note.setText(self.account_state.note)
        if self.account_state.state is AccountState.Invisible:
            self.activity_note.inactiveText = u'(invisible)'
            self.activity_note.setEnabled(False)
        else:
            if not self.activity_note.isEnabled():
                self.activity_note.inactiveText = u'Add an activity note here'
                self.activity_note.setEnabled(True)
        if not self.account_state.state.internal:
            self.saved_account_state = None
        blink_settings = BlinkSettings()
        blink_settings.presence.current_state = PresenceState(self.account_state.state, self.account_state.note)
        blink_settings.presence.state_history = [PresenceState(state, note) for state, note in self.account_state.history]
        blink_settings.save()

    def _SH_AccountStateClicked(self, checked):
        filename = QFileDialog.getOpenFileName(self, u'Select Icon', self.last_icon_directory, u"Images (*.png *.tiff *.jpg *.xmp *.svg)")
        if filename:
            self.last_icon_directory = os.path.dirname(filename)
            filename = filename if os.path.realpath(filename) != os.path.realpath(self.default_icon_path) else None
            blink_settings = BlinkSettings()
            icon_manager = IconManager()
            if filename is not None:
                icon = icon_manager.store_file('avatar', filename)
                if icon is not None:
                    blink_settings.presence.icon = IconDescriptor(FileURL(icon.filename), hashlib.sha1(icon.content).hexdigest())
                else:
                    icon_manager.remove('avatar')
                    blink_settings.presence.icon = None
            else:
                icon_manager.remove('avatar')
                blink_settings.presence.icon = None
            blink_settings.save()

    def _SH_ActivityNoteEditingFinished(self):
        self.activity_note.clearFocus()
        note = self.activity_note.text()
        if note != self.account_state.note:
            self.account_state.state.internal = False
            self.account_state.setState(self.account_state.state, note)

    def _SH_AddContactButtonClicked(self, clicked):
        self.contact_editor_dialog.open_for_add(self.search_box.text(), None)

    def _SH_AudioCallButtonClicked(self):
        list_view = self.contact_list if self.contacts_view.currentWidget() is self.contact_list_panel else self.search_list
        if list_view.detail_view.isVisible():
            list_view.detail_view._AH_StartAudioCall()
        else:
            selected_indexes = list_view.selectionModel().selectedIndexes()
            if selected_indexes:
                contact = selected_indexes[0].data(Qt.UserRole)
                contact_uri = contact.uri
            else:
                contact, contact_uri = URIUtils.find_contact(self.search_box.text())
            session_manager = SessionManager()
            session_manager.create_session(contact, contact_uri, [StreamDescription('audio')])

    def _SH_VideoCallButtonClicked(self):
        list_view = self.contact_list if self.contacts_view.currentWidget() is self.contact_list_panel else self.search_list
        if list_view.detail_view.isVisible():
            list_view.detail_view._AH_StartVideoCall()
        else:
            selected_indexes = list_view.selectionModel().selectedIndexes()
            if selected_indexes:
                contact = selected_indexes[0].data(Qt.UserRole)
                contact_uri = contact.uri
            else:
                contact, contact_uri = URIUtils.find_contact(self.search_box.text())
            session_manager = SessionManager()
            session_manager.create_session(contact, contact_uri, [StreamDescription('audio'), StreamDescription('video')])

    def _SH_ChatSessionButtonClicked(self):
        list_view = self.contact_list if self.contacts_view.currentWidget() is self.contact_list_panel else self.search_list
        if list_view.detail_view.isVisible():
            list_view.detail_view._AH_StartChatSession()
        else:
            selected_indexes = list_view.selectionModel().selectedIndexes()
            if selected_indexes:
                contact = selected_indexes[0].data(Qt.UserRole)
                contact_uri = contact.uri
            else:
                contact, contact_uri = URIUtils.find_contact(self.search_box.text())
            session_manager = SessionManager()
            session_manager.create_session(contact, contact_uri, [StreamDescription('chat')], connect=False)

    def _AH_RequestScreenActionTriggered(self):
        list_view = self.contact_list if self.contacts_view.currentWidget() is self.contact_list_panel else self.search_list
        if list_view.detail_view.isVisible():
            list_view.detail_view._AH_RequestScreen()
        else:
            selected_indexes = list_view.selectionModel().selectedIndexes()
            if selected_indexes:
                contact = selected_indexes[0].data(Qt.UserRole)
                contact_uri = contact.uri
            else:
                contact, contact_uri = URIUtils.find_contact(self.search_box.text())
            session_manager = SessionManager()
            session_manager.create_session(contact, contact_uri, [StreamDescription('screen-sharing', mode='viewer'), StreamDescription('audio')])

    def _AH_ShareMyScreenActionTriggered(self):
        list_view = self.contact_list if self.contacts_view.currentWidget() is self.contact_list_panel else self.search_list
        if list_view.detail_view.isVisible():
            list_view.detail_view._AH_ShareMyScreen()
        else:
            selected_indexes = list_view.selectionModel().selectedIndexes()
            if selected_indexes:
                contact = selected_indexes[0].data(Qt.UserRole)
                contact_uri = contact.uri
            else:
                contact, contact_uri = URIUtils.find_contact(self.search_box.text())
            session_manager = SessionManager()
            session_manager.create_session(contact, contact_uri, [StreamDescription('screen-sharing', mode='server'), StreamDescription('audio')])

    def _SH_BreakConference(self):
        active_session = self.session_list.selectionModel().selectedIndexes()[0].data(Qt.UserRole)
        self.session_model.breakConference(active_session.client_conference)

    def _SH_ContactListSelectionChanged(self, selected, deselected):
        account_manager = AccountManager()
        selected_items = self.contact_list.selectionModel().selectedIndexes()
        self.enable_call_buttons(account_manager.default_account is not None and len(selected_items)==1 and isinstance(selected_items[0].data(Qt.UserRole), Contact))

    def _SH_ContactModelAddedItems(self, items):
        if not self.search_box.text():
            return
        active_widget = self.search_list_panel if self.contact_search_model.rowCount() else self.not_found_panel
        self.search_view.setCurrentWidget(active_widget)

    def _SH_ContactModelRemovedItems(self, items):
        if not self.search_box.text():
            return
        if any(type(item) is Contact for item in items) and self.contact_search_model.rowCount() == 0:
            self.search_box.clear() # check this. it is no longer be the correct behaviour as now contacts can be deleted from remote -Dan
        else:
            active_widget = self.search_list_panel if self.contact_search_model.rowCount() else self.not_found_panel
            self.search_view.setCurrentWidget(active_widget)

    def _SH_DisplayNameEditingFinished(self):
        self.display_name.clearFocus()
        index = self.identity.currentIndex()
        if index != -1:
            name = self.display_name.text()
            account = self.identity.itemData(index).account
            account.display_name = name if name else None
            account.save()

    def _SH_HangupAllButtonClicked(self):
        for session in self.session_model.sessions:
            session.end()

    def _SH_IdentityChanged(self, index):
        account_manager = AccountManager()
        account_manager.default_account = self.identity.itemData(index).account

    def _SH_IdentityCurrentIndexChanged(self, index):
        if index != -1:
            account = self.identity.itemData(index).account
            self.display_name.setText(account.display_name or u'')
            self.display_name.setEnabled(True)
            self.activity_note.setEnabled(True)
            self.account_state.setEnabled(True)
        else:
            self.display_name.clear()
            self.display_name.setEnabled(False)
            self.activity_note.setEnabled(False)
            self.account_state.setEnabled(False)
            self.account_state.setState(AccountState.Invisible)
            self.saved_account_state = None

    def _SH_MakeConference(self):
        self.session_model.conferenceSessions([session for session in self.session_model.active_sessions if session.client_conference is None])

    def _SH_MuteButtonClicked(self, muted):
        settings = SIPSimpleSettings()
        settings.audio.muted = muted
        settings.save()

    def _SH_SearchBoxReturnPressed(self):
        address = self.search_box.text()
        if address:
            contact, contact_uri = URIUtils.find_contact(address)
            session_manager = SessionManager()
            session_manager.create_session(contact, contact_uri, [StreamDescription('audio')])

    def _SH_SearchBoxTextChanged(self, text):
        self.contact_search_model.setFilterFixedString(text)
        account_manager = AccountManager()
        if text:
            self.switch_view_button.view = SwitchViewButton.ContactView
            if self.contacts_view.currentWidget() is not self.search_panel:
                self.search_list.selectionModel().clearSelection()
            self.contacts_view.setCurrentWidget(self.search_panel)
            self.search_view.setCurrentWidget(self.search_list_panel if self.contact_search_model.rowCount() else self.not_found_panel)
            selected_items = self.search_list.selectionModel().selectedIndexes()
            self.enable_call_buttons(account_manager.default_account is not None and len(selected_items)<=1)
        else:
            self.contacts_view.setCurrentWidget(self.contact_list_panel)
            selected_items = self.contact_list.selectionModel().selectedIndexes()
            self.enable_call_buttons(account_manager.default_account is not None and len(selected_items)==1 and type(selected_items[0].data(Qt.UserRole)) is Contact)
        self.search_list.detail_model.contact = None
        self.search_list.detail_view.hide()

    def _SH_SearchListSelectionChanged(self, selected, deselected):
        account_manager = AccountManager()
        selected_items = self.search_list.selectionModel().selectedIndexes()
        self.enable_call_buttons(account_manager.default_account is not None and len(selected_items)<=1)

    def _SH_ServerToolsAccountModelChanged(self, parent_index, start, end):
        server_tools_enabled = self.server_tools_account_model.rowCount() > 0
        self.sip_server_settings_action.setEnabled(server_tools_enabled)
        self.search_for_people_action.setEnabled(server_tools_enabled)
        self.history_on_server_action.setEnabled(server_tools_enabled)

    def _SH_SessionListSelectionChanged(self, selected, deselected):
        selected_indexes = selected.indexes()
        active_session = selected_indexes[0].data(Qt.UserRole) if selected_indexes else Null
        if active_session.client_conference:
            self.conference_button.setEnabled(True)
            self.conference_button.setChecked(True)
        else:
            self.conference_button.setEnabled(len([session for session in self.session_model.active_sessions if session.client_conference is None]) > 1)
            self.conference_button.setChecked(False)

    def _SH_AudioSessionModelAddedSession(self, session_item):
        if len(session_item.blink_session.streams) == 1:
            self.switch_view_button.view = SwitchViewButton.SessionView

    def _SH_AudioSessionModelRemovedSession(self, session_item):
        if self.session_model.rowCount() == 0:
            self.switch_view_button.view = SwitchViewButton.ContactView

    def _SH_AudioSessionModelChangedStructure(self):
        active_sessions = self.session_model.active_sessions
        self.active_sessions_label.setText(u'There is 1 active call' if len(active_sessions)==1 else u'There are %d active calls' % len(active_sessions))
        self.active_sessions_label.setVisible(any(active_sessions))
        self.hangup_all_button.setEnabled(any(active_sessions))
        selected_indexes = self.session_list.selectionModel().selectedIndexes()
        active_session = selected_indexes[0].data(Qt.UserRole) if selected_indexes else Null
        if active_session.client_conference:
            self.conference_button.setEnabled(True)
            self.conference_button.setChecked(True)
        else:
            self.conference_button.setEnabled(len([session for session in active_sessions if session.client_conference is None]) > 1)
            self.conference_button.setChecked(False)
        if active_sessions:
            if self.account_state.state is not AccountState.Invisible:
                if self.saved_account_state is None:
                    self.saved_account_state = self.account_state.state, self.activity_note.text()
                self.account_state.setState(AccountState.Busy.Internal, note=u'On the phone')
        elif self.saved_account_state is not None:
            state, note = self.saved_account_state
            self.saved_account_state = None
            self.account_state.setState(state, note)

    def _SH_SilentButtonClicked(self, silent):
        settings = SIPSimpleSettings()
        settings.audio.silent = silent
        settings.save()

    def _SH_SwitchViewButtonChangedView(self, view):
        self.main_view.setCurrentWidget(self.contacts_panel if view is SwitchViewButton.ContactView else self.sessions_panel)

    def _SH_PendingWatcherDialogFinished(self, result):
        self.pending_watcher_dialogs.remove(self.sender())

    def _SH_SystemTrayIconActivated(self, reason):
        if reason == QSystemTrayIcon.Trigger:
            self.show()
            self.raise_()
            self.activateWindow()

    @run_in_gui_thread
    def handle_notification(self, notification):
        handler = getattr(self, '_NH_%s' % notification.name, Null)
        handler(notification)

    def _NH_SIPApplicationWillStart(self, notification):
        account_manager = AccountManager()
        settings = SIPSimpleSettings()
        self.silent_action.setChecked(settings.audio.silent)
        self.silent_button.setChecked(settings.audio.silent)
        self.answering_machine_action.setChecked(settings.answering_machine.enabled)
        self.auto_accept_chat_action.setChecked(settings.chat.auto_accept)
        self.received_messages_sound_action.setChecked(settings.sounds.play_message_alerts)
        if settings.google_contacts.authorization_token is None:
            self.google_contacts_action.setText(u'Enable &Google Contacts...')
        else:
            self.google_contacts_action.setText(u'Disable &Google Contacts')
        self.google_contacts_action.triggered.connect(self._AH_GoogleContactsActionTriggered)
        if not any(account.enabled for account in account_manager.iter_accounts()):
            self.display_name.setEnabled(False)
            self.activity_note.setEnabled(False)
            self.account_state.setEnabled(False)

    def _NH_SIPApplicationDidStart(self, notification):
        self.load_audio_devices()
        self.load_video_devices()
        notification.center.add_observer(self, name='CFGSettingsObjectDidChange')
        notification.center.add_observer(self, name='AudioDevicesDidChange')
        blink_settings = BlinkSettings()
        self.account_state.history = [(item.state, item.note) for item in blink_settings.presence.state_history]
        state = getattr(AccountState, blink_settings.presence.current_state.state, AccountState.Available)
        self.account_state.setState(state, blink_settings.presence.current_state.note)

    def _NH_AudioDevicesDidChange(self, notification):
        for action in self.output_device_menu.actions():
            self.output_devices_group.removeAction(action)
            self.output_device_menu.removeAction(action)
        for action in self.input_device_menu.actions():
            self.input_devices_group.removeAction(action)
            self.input_device_menu.removeAction(action)
        for action in self.alert_device_menu.actions():
            self.alert_devices_group.removeAction(action)
            self.alert_device_menu.removeAction(action)
        if self.session_model.active_sessions:
            old_devices = set(notification.data.old_devices)
            new_devices = set(notification.data.new_devices)
            added_devices = new_devices - old_devices
            if added_devices:
                new_device = added_devices.pop()
                settings = SIPSimpleSettings()
                settings.audio.input_device = new_device
                settings.audio.output_device = new_device
                settings.save()
        self.load_audio_devices()

    def _NH_CFGSettingsObjectDidChange(self, notification):
        settings = SIPSimpleSettings()
        blink_settings = BlinkSettings()
        icon_manager = IconManager()
        if notification.sender is settings:
            if 'audio.muted' in notification.data.modified:
                self.mute_action.setChecked(settings.audio.muted)
                self.mute_button.setChecked(settings.audio.muted)
            if 'audio.silent' in notification.data.modified:
                self.silent_action.setChecked(settings.audio.silent)
                self.silent_button.setChecked(settings.audio.silent)
            if 'audio.output_device' in notification.data.modified:
                action = (action for action in self.output_devices_group.actions() if action.data() == settings.audio.output_device).next()
                action.setChecked(True)
            if 'audio.input_device' in notification.data.modified:
                action = (action for action in self.input_devices_group.actions() if action.data() == settings.audio.input_device).next()
                action.setChecked(True)
            if 'audio.alert_device' in notification.data.modified:
                action = (action for action in self.alert_devices_group.actions() if action.data() == settings.audio.alert_device).next()
                action.setChecked(True)
            if 'video.device' in notification.data.modified:
                action = (action for action in self.video_devices_group.actions() if action.data() == settings.video.device).next()
                action.setChecked(True)
            if 'answering_machine.enabled' in notification.data.modified:
                self.answering_machine_action.setChecked(settings.answering_machine.enabled)
            if 'chat.auto_accept' in notification.data.modified:
                self.auto_accept_chat_action.setChecked(settings.chat.auto_accept)
            if 'sounds.play_message_alerts' in notification.data.modified:
                self.received_messages_sound_action.setChecked(settings.sounds.play_message_alerts)
            if 'google_contacts.authorization_token' in notification.data.modified:
                authorization_token = notification.sender.google_contacts.authorization_token
                if authorization_token is None:
                    self.google_contacts_action.setText(u'Enable &Google Contacts...')
                else:
                    self.google_contacts_action.setText(u'Disable &Google Contacts')
                if authorization_token is InvalidToken:
                    self.google_contacts_dialog.open_for_incorrect_password()
        elif notification.sender is blink_settings:
            if 'presence.current_state' in notification.data.modified:
                state = getattr(AccountState, blink_settings.presence.current_state.state, AccountState.Available)
                self.account_state.setState(state, blink_settings.presence.current_state.note)
            if 'presence.icon' in notification.data.modified:
                self.set_user_icon(icon_manager.get('avatar'))
            if 'presence.offline_note' in notification.data.modified:
                # TODO: set offline note -Saul
                pass
        elif isinstance(notification.sender, (Account, BonjourAccount)):
            account_manager = AccountManager()
            account = notification.sender
            if 'enabled' in notification.data.modified:
                action = (action for action in self.accounts_menu.actions() if action.data() is account).next()
                action.setChecked(account.enabled)
            if 'display_name' in notification.data.modified and account is account_manager.default_account:
                self.display_name.setText(account.display_name or u'')
            if set(['enabled', 'message_summary.enabled', 'message_summary.voicemail_uri']).intersection(notification.data.modified):
                action = (action for action in self.voicemail_menu.actions() if action.data() is account).next()
                action.setVisible(False if account is BonjourAccount() else account.enabled and account.message_summary.enabled)
                action.setEnabled(False if account is BonjourAccount() else account.voicemail_uri is not None)

    def _NH_SIPAccountManagerDidAddAccount(self, notification):
        account = notification.data.account
        action = QAction(account.id if account is not BonjourAccount() else u'Bonjour', None)
        action.setEnabled(True if account is not BonjourAccount() else BonjourAccount.mdns_available)
        action.setCheckable(True)
        action.setChecked(account.enabled)
        action.setData(account)
        action.triggered.connect(partial(self._AH_AccountActionTriggered, action))
        self.accounts_menu.addAction(action)
        action = QAction(self.mwi_icons[0], account.id, None)
        action.setVisible(False if account is BonjourAccount() else account.enabled and account.message_summary.enabled)
        action.setEnabled(False if account is BonjourAccount() else account.voicemail_uri is not None)
        action.setData(account)
        action.triggered.connect(partial(self._AH_VoicemailActionTriggered, action))
        self.voicemail_menu.addAction(action)

    def _NH_SIPAccountManagerDidRemoveAccount(self, notification):
        account = notification.data.account
        action = (action for action in self.accounts_menu.actions() if action.data() is account).next()
        self.accounts_menu.removeAction(action)
        action = (action for action in self.voicemail_menu.actions() if action.data() is account).next()
        self.voicemail_menu.removeAction(action)

    def _NH_SIPAccountManagerDidChangeDefaultAccount(self, notification):
        if notification.data.account is None:
            self.enable_call_buttons(False)
        else:
            selected_items = self.contact_list.selectionModel().selectedIndexes()
            self.enable_call_buttons(len(selected_items)==1 and isinstance(selected_items[0].data(Qt.UserRole), Contact))

    def _NH_SIPAccountGotMessageSummary(self, notification):
        account = notification.sender
        summary = notification.data.message_summary
        action = (action for action in self.voicemail_menu.actions() if action.data() is account).next()
        action.setEnabled(account.voicemail_uri is not None)
        if summary.messages_waiting:
            try:
                new_messages = limit(int(summary.summaries['voice-message']['new_messages']), min=0, max=11)
            except (KeyError, ValueError):
                new_messages = 0
        else:
            new_messages = 0
        action.setIcon(self.mwi_icons[new_messages])

    def _NH_SIPAccountGotPendingWatcher(self, notification):
        dialog = PendingWatcherDialog(notification.sender, notification.data.uri, notification.data.display_name)
        dialog.finished.connect(self._SH_PendingWatcherDialogFinished)
        self.pending_watcher_dialogs.append(dialog)
        dialog.show()

    def _NH_BlinkSessionNewOutgoing(self, notification):
        self.search_box.clear()

    def _NH_BlinkSessionDidReinitializeForOutgoing(self, notification):
        self.search_box.clear()

    def _NH_FileTransferNewIncoming(self, notification):
        self.filetransfer_window.show(activate=QApplication.activeWindow() is not None)

    def _NH_FileTransferNewOutgoing(self, notification):
        self.filetransfer_window.show(activate=QApplication.activeWindow() is not None)
class PigeonFeather(QMainWindow):
    """Main class for the application, inherits class genrated from pyuic"""

    def __init__(self, parent=None):
        super(PigeonFeather, self).__init__(parent)

        # Check that environment supports systemtray
        if not QSystemTrayIcon.isSystemTrayAvailable():
            print('FATAL: There is no system tray')
            sys.exit(1)

        # Make sure that we can load an icon list
        try:
            with open('code2iconlist.pkl', 'rb') as iconList:
                self.codeToIconList = pickle.load(iconList)
        except (IOError, pickle.PickleError):
            print('FATAL: Could not not load code2iconlist')
            sys.exit(1)

        # See if balloon messages are supported
        #print('Desktop support balloon messages = ' + \
        #    str(QSystemTrayIcon.supportsMessages()))

        # Set the user config fle
        self.USER_CONFIG = os.path.expanduser('~/.pigeonfeather')

        # Load preferences
        self.loadConfig()

        # Class properties
        self.trayIcon = QSystemTrayIcon(self)

        # Weather Dialog and Configure Dialog
        self.weatherDialog = WeatherDialog(self)
        self.configureDialog = ConfigureDialog(self)

        # Set up the application
        self.setup()

    def setup(self):
        """Setup and start the application"""
        # Connect some slots

        # Icon is clicked
        self.connect(self.trayIcon, \
            SIGNAL('activated(QSystemTrayIcon::ActivationReason)'), \
            self.trayIconClicked)

        # Connnect slot emitted from CnfigureDialog to update preferences
        self.connect(self.configureDialog, SIGNAL('ConfigureDialogOk'), \
            self.saveConfig)

        # Set an initial icon for tray and weather dialog
        self.setTrayIcon(QIcon('images/22/dunno.png'))
        self.weatherDialog.labelIcon.setPixmap(QPixmap('images/64/dunno.png'))

        # Set the menu
        self.trayIcon.setContextMenu(self.createMenu())

        # Setup the config dialog with values loaded from config
        woeid = self.config.get('main', 'woeid')

        # If woeid is not valid set a default and use that
        try:
            self.configureDialog.setWoeid(woeid)
        except ValueError as ve:
            self.config.set('main', 'woeid', '2408842')
            self.configureDialog.setWoeid('2408842')

        # Set temperature units
        if self.config.get('units', 'temperature') == 'fahrenheit':
            self.configureDialog.setTemperature('fahrenheit')
        else:
            self.configureDialog.setTemperature('celcius')

        # Set distance units
        if self.config.get('units', 'distance') == 'km':
            self.configureDialog.setDistance('km')
        else:
            self.configureDialog.setDistance('mi')

        # Set wind units
        if self.config.get('units', 'wind') == 'kph':
            self.configureDialog.setWind('kph')
        else:
            self.configureDialog.setWind('mph')

        # Set pressure units
        if self.config.get('units', 'pressure') == 'mb':
            self.configureDialog.setPressure('mb')
        else:
            self.configureDialog.setPressure('in')

        # Start getWeather thread with Id from config
        # Connect two slots for the two signals emitted from thread
        self.getWeatherThread = GetWeatherQThread(self.config.get( \
            'main', 'woeid'))
        self.getWeatherThread.start()

        self.connect(self.getWeatherThread, SIGNAL('WeatherUpdate'), \
            self.processWeather)
        self.connect(self.getWeatherThread, SIGNAL('WeatherReadError'), \
            self.showErrorMessage)

    def loadConfig(self):
        """Load preferences from defaults then self.USER_CONFIG if exists"""
        # Load a default set first
        defaultConfig = io.StringIO("""\
[main]
Woeid=2408842
[units]
temperature=celcius
wind=mph
pressure=mb
distance=mi
""")

        self.config = ConfigParser()

        # Load defaults
        self.config.readfp(defaultConfig)

        # Load config if it exists
        self.config.read(self.USER_CONFIG)

    def createMenu(self):
        """Create and return the applications menu"""
        menu = QMenu(self)
        menu.addAction(QIcon('images/22/sunny.png'), '&Show Weather Report', \
            self.showWeatherDialog)
        menu.addAction(QIcon('images/22/configure.png'), '&Configure', \
            self.showConfigureDialog)
        menu.addAction(QIcon('images/22/help.png'), '&About', \
            self.showAboutDialog)
        menu.addAction(QIcon('images/22/exit.png'), '&Exit', self.quitApp)
        return menu

    def saveConfig(self, config):
        """Save the recieved config back to the config file and update the
        local copy in the object

        Keyword arguments:
        config -- A dict. of config recieved from the configuration dialog
        """
        # Set the local config object and try and save it
        self.config.set('main', 'woeid', config['woeid'])
        self.config.set('units', 'temperature', config['temperature'])
        self.config.set('units', 'wind', config['wind'])
        self.config.set('units', 'pressure', config['pressure'])
        self.config.set('units', 'distance', config['distance'])

        # Update the Weoid in the get weather thread
        self.getWeatherThread.setWoeid(config['woeid'])

        # Try and save the config
        try:
            with open(self.USER_CONFIG, 'wb') as configfile:
                self.config.write(configfile)
        except IOError as ioe:
            self.showErrorMessage('Could not save configuration settings' + \
                'to disk')

    def showErrorMessage(self, message):
        """Show a error as a tray balloon message

        Keyword arguments:
        message -- Error message to display
        """
        self.trayIcon.showMessage('Application Error', message, \
            QSystemTrayIcon.Critical)

    def trayIconClicked(self, reason):
        """If the tray icon is left clicked, show/hide the weather dialog
        If this is called on a Darwin(mac) machine do not pop up.  This follows
        better mac convention

        Keyword arguments:
        reason -- A QSystemTrayIcon.ActivationReason enum
        """
        # If mac then ignore click
        if platform.system() == 'Darwin':
            return

        # Test for left click
        if reason == 3:
            if self.weatherDialog.isVisible():
                self.weatherDialog.hide()
            else:
                self.weatherDialog.show()

    def showWeatherDialog(self):
        """Show the weather report dialog"""
        self.weatherDialog.show()

    def showConfigureDialog(self):
        """Show the configure dialog"""
        self.configureDialog.show()

    def showAboutDialog(self):
        """Show the about pyqtweather dialog"""
        QMessageBox.about(None, 'About Pigeon Feather', 'Pigeon Feather\n \
            (c) 2010 Ben Sampson\nPigeon Feather uses the Yahoo! Weather API\n\
            License: GNU General Public License Version 3')

    def processWeather(self, weather):
        """Slot that is called by the weather thread, responsible for updating
        the GUI with the new weather data, this includes the trayicon and
        tooltip and the weather report dialog

        Keyword arguments:
        weather -- map of weather data
        """
        # TODO These should really call setter methods on weather dialog

        # Copy weather to local vars basd on preferences
        fetched = weather['fetched']

        code = weather['code']
        if self.config.get('units', 'temperature') == 'celcius':
            temp = weather['tempC']
            chill = weather['chillC']
            tempUnit = 'C'
        else:
            temp = weather['tempF']
            chill = weather['chillF']
            tempUnit = 'F'

        text = weather['text']
        city = weather['city']
        region = weather['region']
        country = weather['country']

        sunrise = weather['sunrise']
        sunset = weather['sunset']

        if self.config.get('units', 'wind') == 'mph':
            windSpeed = weather['windSpeedMph']
            speedUnit = 'mph'
        else:
            windSpeed = weather['windSpeedKph']
            speedUnit = 'kph'

        if self.config.get('units', 'pressure') == 'mb':
            pressure = weather['pressureMb']
            pressureUnit = 'mb'
        else:
            pressure = weather['pressureIn']
            pressureUnit = 'in'

        directionTextual = weather['directionTextual']
        pressureTendancy = weather['pressureTendancy']
        humidity = weather['humidity']

        if self.config.get('units', 'distance') == 'mi':
            visibility = weather['visibilityMi']
            distanceUnit = 'mi'
        else:
            visibility = weather['visibilityKm']
            distanceUnit = 'km'

        # Get the filename for the icon to disply from the icon list map
        # Generate the system tray icon and set it
        iconFileName = self.codeToIconList[int(code)][1]
        icon = self.createWeatherIcon('images/22/' + iconFileName, str(temp))
        self.setTrayIcon(icon)

        # Set the tool tip
        tempString = str(temp) + '°' + tempUnit + ' ' + text
        self.trayIcon.setToolTip(tempString)

        # Update the weather report dialog
        self.weatherDialog.labelLastUpdate.setText( \
            fetched.strftime('%H:%M:%S'))
        self.weatherDialog.setWindowTitle('Weather report for ' + city + \
            ', ' + region + ' ' + country)
        self.weatherDialog.labelTemp.setText(tempString)
        self.weatherDialog.labelSunrise.setText(sunrise)
        self.weatherDialog.labelSunset.setText(sunset)
        self.weatherDialog.labelWindChill.setText(str(chill) + \
            '°' + tempUnit)
        self.weatherDialog.labelWindSpeed.setText(str(windSpeed) + ' ' + \
            speedUnit)
        self.weatherDialog.labelWindDirection.setText(directionTextual)
        self.weatherDialog.labelHumidity.setText(str(humidity) + '%')
        self.weatherDialog.labelVisibility.setText(str(visibility) + ' ' + \
            distanceUnit)
        self.weatherDialog.labelPressure.setText(str(pressure) + ' ' + \
            pressureUnit)
        self.weatherDialog.labelRising.setText(pressureTendancy)

        # Set the image
        self.weatherDialog.labelIcon.setPixmap(QPixmap('images/64/' + \
          iconFileName))

    # TODO - this should really be in another class
    def createWeatherIcon(self, iconFileName, temp):
        """Create the icon to display in the tray"""
        # Create a map of what image to use based on code
        # Start by creating a transparent image to paint on
        print(('Using' + iconFileName))
        icon = QPixmap(22, 22)
        icon.fill(Qt.transparent)

        # Create a painter to paint on to the icon and draw on the text
        painter = QPainter(icon)
        painter.setOpacity(0.5)

        # Draw text of temperature
        font = QFont('Times', 10, QFont.Black)
        painter.setFont(font)
        painter.setPen(QColor('red'))
        painter.drawPixmap(QPoint(0, 0), QPixmap(iconFileName))
        painter.setOpacity(1)
        painter.drawText(5, 15, temp)
        painter.end()

        # Return the icon
        return QIcon(icon)

    def setTrayIcon(self, icon):
        """Set the tray icon"""
        self.trayIcon.setIcon(icon)
        self.trayIcon.show()

    def quitApp(self):
        """Exit the application"""
        sys.exit(0)
示例#30
0
class GlobalSysTray(object):
    def __init__(self, parent, name, icon):
        object.__init__(self)

        self._app    = None
        self._parent = parent
        self._gtk_running = False
        self._quit_added  = False

        self.act_indexes  = []
        self.sep_indexes  = []
        self.menu_indexes = []

        if TrayEngine == "KDE":
            self.menu = KMenu(parent)
            self.menu.setTitle(name)
            self.tray = KStatusNotifierItem()
            self.tray.setAssociatedWidget(parent)
            self.tray.setCategory(KStatusNotifierItem.ApplicationStatus)
            self.tray.setContextMenu(self.menu)
            self.tray.setIconByPixmap(getIcon(icon))
            self.tray.setTitle(name)
            self.tray.setToolTipTitle(" ")
            self.tray.setToolTipIconByPixmap(getIcon(icon))
            # Double-click is managed by KDE

        elif TrayEngine == "AppIndicator":
            self.menu = Gtk.Menu()
            self.tray = AppIndicator.Indicator.new(name, icon, AppIndicator.IndicatorCategory.APPLICATION_STATUS)
            self.tray.set_menu(self.menu)
            # Double-click is not possible with App-Indicators

        elif TrayEngine == "Qt":
            self.menu = QMenu(parent)
            self.tray = QSystemTrayIcon(getIcon(icon))
            self.tray.setContextMenu(self.menu)
            self.tray.setParent(parent)
            self.tray.connect(self.tray, SIGNAL("activated(QSystemTrayIcon::ActivationReason)"), self.qt_systray_clicked)

    # -------------------------------------------------------------------------------------------

    def addAction(self, act_name_id, act_name_string, is_check=False):
        if TrayEngine == "KDE":
            act_widget = KAction(act_name_string, self.menu)
            act_widget.setCheckable(is_check)
            self.menu.addAction(act_widget)

        elif TrayEngine == "AppIndicator":
            if is_check:
                act_widget = Gtk.CheckMenuItem(act_name_string)
            else:
                act_widget = Gtk.ImageMenuItem(act_name_string)
                act_widget.set_image(None)
            act_widget.show()
            self.menu.append(act_widget)

        elif TrayEngine == "Qt":
            act_widget = QAction(act_name_string, self.menu)
            act_widget.setCheckable(is_check)
            self.menu.addAction(act_widget)

        else:
            act_widget = None

        act_obj = [None, None, None, None]
        act_obj[iActNameId] = act_name_id
        act_obj[iActWidget] = act_widget

        self.act_indexes.append(act_obj)

    def addSeparator(self, sep_name_id):
        if TrayEngine == "KDE":
            sep_widget = self.menu.addSeparator()

        elif TrayEngine == "AppIndicator":
            sep_widget = Gtk.SeparatorMenuItem()
            sep_widget.show()
            self.menu.append(sep_widget)

        elif TrayEngine == "Qt":
            sep_widget = self.menu.addSeparator()

        else:
            sep_widget = None

        sep_obj = [None, None, None]
        sep_obj[iSepNameId] = sep_name_id
        sep_obj[iSepWidget] = sep_widget

        self.sep_indexes.append(sep_obj)

    def addMenu(self, menu_name_id, menu_name_string):
        if TrayEngine == "KDE":
            menu_widget = KMenu(menu_name_string, self.menu)
            self.menu.addMenu(menu_widget)

        elif TrayEngine == "AppIndicator":
            menu_widget = Gtk.MenuItem(menu_name_string)
            menu_parent = Gtk.Menu()
            menu_widget.set_submenu(menu_parent)
            menu_widget.show()
            self.menu.append(menu_widget)

        elif TrayEngine == "Qt":
            menu_widget = QMenu(menu_name_string, self.menu)
            self.menu.addMenu(menu_widget)

        else:
            menu_widget = None

        menu_obj = [None, None, None]
        menu_obj[iMenuNameId] = menu_name_id
        menu_obj[iMenuWidget] = menu_widget

        self.menu_indexes.append(menu_obj)

    # -------------------------------------------------------------------------------------------

    def addMenuAction(self, menu_name_id, act_name_id, act_name_string, is_check=False):
        i = self.get_menu_index(menu_name_id)
        if i < 0: return

        menu_widget = self.menu_indexes[i][iMenuWidget]

        if TrayEngine == "KDE":
            act_widget = KAction(act_name_string, menu_widget)
            act_widget.setCheckable(is_check)
            menu_widget.addAction(act_widget)

        elif TrayEngine == "AppIndicator":
            menu_widget = menu_widget.get_submenu()
            if is_check:
                act_widget = Gtk.CheckMenuItem(act_name_string)
            else:
                act_widget = Gtk.ImageMenuItem(act_name_string)
                act_widget.set_image(None)
            act_widget.show()
            menu_widget.append(act_widget)

        elif TrayEngine == "Qt":
            act_widget = QAction(act_name_string, menu_widget)
            act_widget.setCheckable(is_check)
            menu_widget.addAction(act_widget)

        else:
            act_widget = None

        act_obj = [None, None, None, None]
        act_obj[iActNameId] = act_name_id
        act_obj[iActWidget] = act_widget
        act_obj[iActParentMenuId] = menu_name_id

        self.act_indexes.append(act_obj)

    def addMenuSeparator(self, menu_name_id, sep_name_id):
        i = self.get_menu_index(menu_name_id)
        if i < 0: return

        menu_widget = self.menu_indexes[i][iMenuWidget]

        if TrayEngine == "KDE":
            sep_widget = menu_widget.addSeparator()

        elif TrayEngine == "AppIndicator":
            menu_widget = menu_widget.get_submenu()
            sep_widget = Gtk.SeparatorMenuItem()
            sep_widget.show()
            menu_widget.append(sep_widget)

        elif TrayEngine == "Qt":
            sep_widget = menu_widget.addSeparator()

        else:
            sep_widget = None

        sep_obj = [None, None, None]
        sep_obj[iSepNameId] = sep_name_id
        sep_obj[iSepWidget] = sep_widget
        sep_obj[iSepParentMenuId] = menu_name_id

        self.sep_indexes.append(sep_obj)

    #def addSubMenu(self, menu_name_id, new_menu_name_id, new_menu_name_string):
        #menu_index = self.get_menu_index(menu_name_id)
        #if menu_index < 0: return
        #menu_widget = self.menu_indexes[menu_index][1]
        ##if TrayEngine == "KDE":
            ##new_menu_widget = KMenu(new_menu_name_string, self.menu)
            ##menu_widget.addMenu(new_menu_widget)
        ##elif TrayEngine == "AppIndicator":
            ##new_menu_widget = Gtk.MenuItem(new_menu_name_string)
            ##new_menu_widget.show()
            ##menu_widget.get_submenu().append(new_menu_widget)
            ##parent_menu_widget = Gtk.Menu()
            ##new_menu_widget.set_submenu(parent_menu_widget)
        ##else:
        #if (1):
            #new_menu_widget = QMenu(new_menu_name_string, self.menu)
            #menu_widget.addMenu(new_menu_widget)
        #self.menu_indexes.append([new_menu_name_id, new_menu_widget, menu_name_id])

    # -------------------------------------------------------------------------------------------

    def connect(self, act_name_id, act_func):
        i = self.get_act_index(act_name_id)
        if i < 0: return

        act_widget = self.act_indexes[i][iActWidget]

        if TrayEngine == "KDE":
            self.tray.connect(act_widget, SIGNAL("triggered()"), act_func)

        elif TrayEngine == "AppIndicator":
            act_widget.connect("activate", self.gtk_call_func, act_name_id)

        elif TrayEngine == "Qt":
            self.tray.connect(act_widget, SIGNAL("triggered()"), act_func)

        self.act_indexes[i][iActFunc] = act_func

    # -------------------------------------------------------------------------------------------

    #def setActionChecked(self, act_name_id, yesno):
        #index = self.get_act_index(act_name_id)
        #if index < 0: return
        #act_widget = self.act_indexes[index][1]
        ##if TrayEngine == "KDE":
            ##act_widget.setChecked(yesno)
        ##elif TrayEngine == "AppIndicator":
            ##if type(act_widget) != Gtk.CheckMenuItem:
                ##return # Cannot continue
            ##act_widget.set_active(yesno)
        ##else:
        #if (1):
            #act_widget.setChecked(yesno)

    def setActionEnabled(self, act_name_id, yesno):
        i = self.get_act_index(act_name_id)
        if i < 0: return

        act_widget = self.act_indexes[i][iActWidget]

        if TrayEngine == "KDE":
            act_widget.setEnabled(yesno)

        elif TrayEngine == "AppIndicator":
            act_widget.set_sensitive(yesno)

        elif TrayEngine == "Qt":
            act_widget.setEnabled(yesno)

    def setActionIcon(self, act_name_id, icon):
        i = self.get_act_index(act_name_id)
        if i < 0: return

        act_widget = self.act_indexes[i][iActWidget]

        if TrayEngine == "KDE":
            act_widget.setIcon(KIcon(icon))

        elif TrayEngine == "AppIndicator":
            if not isinstance(act_widget, Gtk.ImageMenuItem):
                # Cannot use icons here
                return

            act_widget.set_image(Gtk.Image.new_from_icon_name(icon, Gtk.IconSize.MENU))
            #act_widget.set_always_show_image(True)

        elif TrayEngine == "Qt":
            act_widget.setIcon(getIcon(icon))

    def setActionText(self, act_name_id, text):
        i = self.get_act_index(act_name_id)
        if i < 0: return

        act_widget = self.act_indexes[i][iActWidget]

        if TrayEngine == "KDE":
            act_widget.setText(text)

        elif TrayEngine == "AppIndicator":
            if isinstance(act_widget, Gtk.ImageMenuItem):
                # Fix icon reset
                last_icon = act_widget.get_image()
                act_widget.set_label(text)
                act_widget.set_image(last_icon)
            else:
                act_widget.set_label(text)

        elif TrayEngine == "Qt":
            act_widget.setText(text)

    def setIcon(self, icon):
        if TrayEngine == "KDE":
            self.tray.setIconByPixmap(getIcon(icon))
            #self.tray.setToolTipIconByPixmap(getIcon(icon))

        elif TrayEngine == "AppIndicator":
            self.tray.set_icon(icon)

        elif TrayEngine == "Qt":
            self.tray.setIcon(getIcon(icon))

    def setToolTip(self, text):
        if TrayEngine == "KDE":
            self.tray.setToolTipSubTitle(text)

        elif TrayEngine == "AppIndicator":
            # ToolTips are disabled in App-Indicators by design
            pass

        elif TrayEngine == "Qt":
            self.tray.setToolTip(text)

    # -------------------------------------------------------------------------------------------

    #def removeAction(self, act_name_id):
        #index = self.get_act_index(act_name_id)
        #if index < 0: return
        #act_widget = self.act_indexes[index][1]
        #parent_menu_widget = self.get_parent_menu_widget(self.act_indexes[index][2])
        ##if TrayEngine == "KDE":
            ##parent_menu_widget.removeAction(act_widget)
        ##elif TrayEngine == "AppIndicator":
            ##act_widget.hide()
            ##parent_menu_widget.remove(act_widget)
        ##else:
        #if (1):
            #parent_menu_widget.removeAction(act_widget)
        #self.act_indexes.pop(index)

    #def removeSeparator(self, sep_name_id):
        #index = self.get_sep_index(sep_name_id)
        #if index < 0: return
        #sep_widget = self.sep_indexes[index][1]
        #parent_menu_widget = self.get_parent_menu_widget(self.sep_indexes[index][2])
        ##if TrayEngine == "KDE":
            ##parent_menu_widget.removeAction(sep_widget)
        ##elif TrayEngine == "AppIndicator":
            ##sep_widget.hide()
            ##parent_menu_widget.remove(sep_widget)
        ##else:
        #if (1):
            #parent_menu_widget.removeAction(sep_widget)
        #self.sep_indexes.pop(index)

    #def removeMenu(self, menu_name_id):
        #index = self.get_menu_index(menu_name_id)
        #if index < 0: return
        #menu_widget = self.menu_indexes[index][1]
        #parent_menu_widget = self.get_parent_menu_widget(self.menu_indexes[index][2])
        ##if TrayEngine == "KDE":
            ##parent_menu_widget.removeAction(menu_widget.menuAction())
        ##elif TrayEngine == "AppIndicator":
            ##menu_widget.hide()
            ##parent_menu_widget.remove(menu_widget.get_submenu())
        ##else:
        #if (1):
            #parent_menu_widget.removeAction(menu_widget.menuAction())
        #self.remove_actions_by_menu_name_id(menu_name_id)
        #self.remove_separators_by_menu_name_id(menu_name_id)
        #self.remove_submenus_by_menu_name_id(menu_name_id)

    # -------------------------------------------------------------------------------------------

    #def clearAll(self):
        ##if TrayEngine == "KDE":
            ##self.menu.clear()
        ##elif TrayEngine == "AppIndicator":
            ##for child in self.menu.get_children():
                ##self.menu.remove(child)
        ##else:
        #if (1):
            #self.menu.clear()

        #self.act_indexes = []
        #self.sep_indexes = []
        #self.menu_indexes = []

    #def clearMenu(self, menu_name_id):
        #menu_index = self.get_menu_index(menu_name_id)
        #if menu_index < 0: return
        #menu_widget = self.menu_indexes[menu_index][1]
        ##if TrayEngine == "KDE":
            ##menu_widget.clear()
        ##elif TrayEngine == "AppIndicator":
            ##for child in menu_widget.get_submenu().get_children():
                ##menu_widget.get_submenu().remove(child)
        ##else:
        #if (1):
            #menu_widget.clear()
        #list_of_submenus = [menu_name_id]
        #for x in range(0, 10): # 10x level deep, should cover all cases...
            #for this_menu_name_id, menu_widget, parent_menu_id in self.menu_indexes:
                #if parent_menu_id in list_of_submenus and this_menu_name_id not in list_of_submenus:
                    #list_of_submenus.append(this_menu_name_id)
        #for this_menu_name_id in list_of_submenus:
            #self.remove_actions_by_menu_name_id(this_menu_name_id)
            #self.remove_separators_by_menu_name_id(this_menu_name_id)
            #self.remove_submenus_by_menu_name_id(this_menu_name_id)

    # -------------------------------------------------------------------------------------------

    def getTrayEngine(self):
        return TrayEngine

    def isTrayAvailable(self):
        if TrayEngine in ("KDE", "Qt"):
            return QSystemTrayIcon.isSystemTrayAvailable()
        elif TrayEngine == "AppIndicator":
            # Ubuntu/Unity always has a systray
            return True
        else:
            return False

    def handleQtCloseEvent(self, event):
        if self.isTrayAvailable() and self._parent.isVisible():
            event.accept()
            self.__hideShowCall()
            return

        self.close()
        QMainWindow.closeEvent(self._parent, event)

    # -------------------------------------------------------------------------------------------

    def show(self):
        if not self._quit_added:
            self._quit_added = True

            if TrayEngine != "KDE":
                self.addSeparator("_quit")
                self.addAction("show", self._parent.tr("Minimize"))
                self.addAction("quit", self._parent.tr("Quit"))
                self.setActionIcon("quit", "application-exit")
                self.connect("show", self.__hideShowCall)
                self.connect("quit", self.__quitCall)

        if TrayEngine == "KDE":
            self.tray.setStatus(KStatusNotifierItem.Active)
        elif TrayEngine == "AppIndicator":
            self.tray.set_status(AppIndicator.IndicatorStatus.ACTIVE)
        elif TrayEngine == "Qt":
            self.tray.show()

    def hide(self):
        if TrayEngine == "KDE":
            self.tray.setStatus(KStatusNotifierItem.Passive)
        elif TrayEngine == "AppIndicator":
            self.tray.set_status(AppIndicator.IndicatorStatus.PASSIVE)
        elif TrayEngine == "Qt":
            self.tray.hide()

    def close(self):
        if TrayEngine == "KDE":
            self.menu.close()
        elif TrayEngine == "AppIndicator":
            if self._gtk_running:
                self._gtk_running = False
                Gtk.main_quit()
        elif TrayEngine == "Qt":
            self.menu.close()

    def exec_(self, app):
        self._app = app
        if TrayEngine == "AppIndicator":
            self._gtk_running = True
            return Gtk.main()
        else:
            return app.exec_()

    # -------------------------------------------------------------------------------------------

    def get_act_index(self, act_name_id):
        for i in range(len(self.act_indexes)):
            if self.act_indexes[i][iActNameId] == act_name_id:
                return i
        else:
            print("systray.py - Failed to get action index for %s" % act_name_id)
            return -1

    def get_sep_index(self, sep_name_id):
        for i in range(len(self.sep_indexes)):
            if self.sep_indexes[i][iSepNameId] == sep_name_id:
                return i
        else:
            print("systray.py - Failed to get separator index for %s" % sep_name_id)
            return -1

    def get_menu_index(self, menu_name_id):
        for i in range(len(self.menu_indexes)):
            if self.menu_indexes[i][iMenuNameId] == menu_name_id:
                return i
        else:
            print("systray.py - Failed to get menu index for %s" % menu_name_id)
            return -1

    #def get_parent_menu_widget(self, parent_menu_id):
        #if parent_menu_id != None:
            #menu_index = self.get_menu_index(parent_menu_id)
            #if menu_index >= 0:
                #return self.menu_indexes[menu_index][1]
            #else:
                #print("systray.py::Failed to get parent Menu widget for", parent_menu_id)
                #return None
        #else:
            #return self.menu

    #def remove_actions_by_menu_name_id(self, menu_name_id):
        #h = 0
        #for i in range(len(self.act_indexes)):
            #act_name_id, act_widget, parent_menu_id, act_func = self.act_indexes[i - h]
            #if parent_menu_id == menu_name_id:
                #self.act_indexes.pop(i - h)
                #h += 1

    #def remove_separators_by_menu_name_id(self, menu_name_id):
        #h = 0
        #for i in range(len(self.sep_indexes)):
            #sep_name_id, sep_widget, parent_menu_id = self.sep_indexes[i - h]
            #if parent_menu_id == menu_name_id:
                #self.sep_indexes.pop(i - h)
                #h += 1

    #def remove_submenus_by_menu_name_id(self, submenu_name_id):
        #h = 0
        #for i in range(len(self.menu_indexes)):
            #menu_name_id, menu_widget, parent_menu_id = self.menu_indexes[i - h]
            #if parent_menu_id == submenu_name_id:
                #self.menu_indexes.pop(i - h)
                #h += 1

    # -------------------------------------------------------------------------------------------

    def gtk_call_func(self, gtkmenu, act_name_id):
        i = self.get_act_index(act_name_id)
        if i < 0: return None

        return self.act_indexes[i][iActFunc]

    def qt_systray_clicked(self, reason):
        if reason in (QSystemTrayIcon.DoubleClick, QSystemTrayIcon.Trigger):
            self.__hideShowCall()

    # -------------------------------------------------------------------------------------------

    def __hideShowCall(self):
        if self._parent.isVisible():
            self.setActionText("show", self._parent.tr("Restore"))
            self._parent.hide()

            if self._app:
                self._app.setQuitOnLastWindowClosed(False)

        else:
            self.setActionText("show", self._parent.tr("Minimize"))

            if self._parent.isMaximized():
                self._parent.showMaximized()
            else:
                self._parent.showNormal()

            if self._app:
                self._app.setQuitOnLastWindowClosed(True)

            QTimer.singleShot(500, self.__raiseWindow)

    def __quitCall(self):
        if self._app:
            self._app.setQuitOnLastWindowClosed(True)

        self._parent.hide()
        self._parent.close()

    def __raiseWindow(self):
        self._parent.activateWindow()
        self._parent.raise_()
示例#31
0
class Example(QtGui.QMainWindow):

    
	def __init__(self):
	        super(Example, self).__init__()
		

		self.path=sys.path[0]
		f=open('%s/ACCESS_KEY'% self.path,'r')
		f1=open('%s/ACCESS_SECRET'% self.path,'r')
		f2=open('%s/user_info'% self.path)
		self.user_name=f2.readline().strip('\n')
		self.user_id=f2.readline().strip('\n')
		self.a=f.readline().strip('\n')
		self.b=f1.readline().strip('\n')
		f.close()
		f1.close()
		f2.close()
		self.initUI()
		
	def initUI(self):   
		
		self.icon=QSystemTrayIcon()
		self.icon.isSystemTrayAvailable() 
		self.icon.setIcon( QtGui.QIcon('%s/web.png'% self.path) )
		self.icon.setToolTip ( 'dubbleclick to maximize')
		self.icon.show()
		self.icon.activated.connect(self.activate)
		self.setWindowFlags(QtCore.Qt.FramelessWindowHint)
                self.setAttribute(QtCore.Qt.WA_TranslucentBackground)
		self.setGeometry(300, 300, 1500, 1000)
		frame = QtGui.QFrame(parent=self)
                frame.setStyleSheet("QFrame {background: rgba(0,0,0,50%)}")
		box=QtGui.QHBoxLayout()
		
		self.edit = QtGui.QLineEdit()
        	self.edit.setStyleSheet("background: rgba(0,0,0,100%); "" font-weight : bold;" "color:  rgb(250,250,250);""border:5px solid ")
		self.edit.setToolTip('please  <b>Enter your tweet here </b> ')
		self.edit.returnPressed.connect(self.returnPressed)
                box.addWidget(self.edit)	
		
		frame.setLayout(box)
	

		qbtn1 = QtGui.QPushButton('quit', self)
	        qbtn1.clicked.connect(self.close)
		qbtn1.setStyleSheet( "background: rgba(0,0,0,100%); "" font-weight : bold;" "color:  rgb(250,250,250);""border:5px solid ")
	        box.addWidget(qbtn1)
		self.statusBar().setStyleSheet("background: rgba(0,0,0,100%);"" font-weight : bold;" "color:  rgb(250,250,250)")
		self.statusBar().showMessage('Press Enter to send Tweet and press ESC to minimize to tray ')

		
		self.setCentralWidget(frame)  
		self.setWindowIcon(QtGui.QIcon('%s/web.png' % self. path)) 
		

	        self.setWindowTitle('Tweet Fast ')
		self.center()    
	        self.show()
		self.twitter_auth()
		
	def twitter_auth(self):
		
		CONSUMER_KEY = 'VQLDtkDTlbAmT95m5cMsYQ'
		CONSUMER_SECRET = 'bAC0BF69qiEVARJlfFJZZCDQ9mrcqofq16ilQ4OjU'      
		ACCESS_KEY=self.a
		ACCESS_SECRET=self.b
		self.auth = tweepy.OAuthHandler(CONSUMER_KEY, CONSUMER_SECRET)
		self.auth.set_access_token(ACCESS_KEY, ACCESS_SECRET)
	        

	def keyPressEvent(self, e):
		if e.key() == QtCore.Qt.Key_Escape:
			print 'Escape wass pressed '
			self.icon.show()
			
                        self.hide()
	def activate(self,reason ):
			print reason 
			if reason==2:
				self.show()
	
	def center(self):
        
	        qr = self.frameGeometry()
	        cp = QtGui.QDesktopWidget().availableGeometry().center()
	        qr.moveCenter(cp)
	        self.move(qr.topLeft())

	def returnPressed(self):
		path=sys.path[0]
		tweet = self.edit.text()
		api = tweepy.API(self.auth)
		self.statusBar().showMessage('Sending... ')
		api.update_status(tweet) 
		self.statusBar().showMessage('Your Tweet was send ')
		n = pynotify.Notification(" @ %s "% self.user_name , "your tweet was send ","%s/%s.jpg" % (path,self.user_id))
                n.set_hint('x', 200)
                n.set_hint('y', 400)
                pynotify.init('n')		
                n.show()
		self.statusBar().showMessage('Press Enter to send Tweet and press ESC to minimize to tray ')
		self.edit.clear()
示例#32
0
class Platform(QObject):
    def __init__(self):
        QObject.__init__(self)
        documentsLocation = QDesktopServices.storageLocation(QDesktopServices.DocumentsLocation)
        self.databaseFile = os.path.join(documentsLocation, "quickpanel.db")
        self._settings = _Settings(self.databaseFile)
        self.globalKey = GlobalKey()
        self.quickPanel = QuickPanel(self)
        self.actionConfigure = QAction(QIcon(":/images/configure.png"), \
                self.trUtf8("&Configure"), self)
        self.actionExit = QAction(QIcon(":/images/close.png"), \
                self.trUtf8("&Exit"), self)
        self.trayIcon = QSystemTrayIcon(QIcon(":/images/angelfish.png"))
        self.contextMenu = QMenu()
        self.contextMenu.addAction(self.actionConfigure)
        self.contextMenu.addAction(self.actionExit)
        self.trayIcon.setContextMenu(self.contextMenu)
        self.actionConfigure.triggered.connect(self.configure)
        self.actionExit.triggered.connect(self.exit)
        self.trayIcon.activated.connect(self.onTrayIconActivated)

    def start(self):
        self.loadSettings()
        self.trayIcon.show()
        self.quickPanel.initWidgets()
        logger.info("QuickPanel is launched.")
        self.quickPanel.addQuickAccessShortcut(self.trUtf8("Tetrix"), \
                QIcon(":/images/tetrix.png"), self.startTetrix)
        self.quickPanel.addQuickAccessShortcut(self.trUtf8("Hello"), \
                QIcon(":/images/hello.png"), self.sayHello)

    def startTetrix(self):
        if getattr(self, "tetrixWindow", None) is None:
            self.tetrixWindow = TetrixWindow()
        self.tetrixWindow.show()
        self.tetrixWindow.activateWindow()

    def sayHello(self):
        QMessageBox.information(None, self.trUtf8("Say Hello."), \
                self.trUtf8("Hello, world!"))

    def loadSettings(self):
        settings = self.getSettings()
        keyname = settings.value("globalkey", "Alt+`")
        self.keyId = self.globalKey.addHotKey("actionToggleQuickPanel", keyname)
        self.globalKey.catched.connect(self.quickPanel.toggle)

    def saveSettings(self):
        pass

    def configure(self):
        d = ConfigureDialog()
        settings = self.getSettings()
        keyname = settings.value("globalkey", "Alt+`")
        d.setGlobalKey(keyname)
        self.globalKey.removeHotKey(self.keyId)
        try:
            result = getattr(d, "exec")()
        except AttributeError:
            result = getattr(d, "exec_")()
        if result == QDialog.Accepted:
            keyname = d.getGlobalKey()
            settings.setValue("globalkey", keyname)
        self.keyId = self.globalKey.addHotKey("actionToggleQuickPanel", keyname)

    def exit(self):
        self.quickPanel.finalize()
        self.saveSettings()
        self.globalKey.close()
        logger.info("QuickPanel is shutting down.")
        QApplication.instance().quit()

    def onTrayIconActivated(self, reason):
        if reason == QSystemTrayIcon.Trigger:
            self.quickPanel.toggle()

    def getSettings(self):
        return Settings(self._settings)
示例#33
0
class SingleApplication(QApplication):
    def __init__(self, *args):
        QApplication.__init__(self, *args)
        self._memory = QSharedMemory(self)
        self._memory.setKey("d2mp")
        if self._memory.attach():
            self._running = True
        else:
            self._running = False
            if not self._memory.create(1):
                raise RuntimeError(self._memory.errorString().toLocal8Bit().data())

    def is_running(self):
        return self._running
    
    def exec_(self):
        self._create_tray_icon()
        self._create_mod_manager()
        self._start_file_watcher()
        self._create_socket()
        Settings()
        
        return super(SingleApplication, self).exec_()
    def _create_mod_manager(self):
        self.manager = ModManager()
        self.manager.mod_game_info()
        self.manager.signals.message.connect(self.show_message_from_mod_manager)
        self.manager.signals.error.connect(self.show_error_from_mod_manager)
    
    def _create_socket(self):    
        self.socket = ConnectionManager()
        
        self.manager.signals.contact_server.connect(self.socket.send)
        
        self.socket.message.connect(self.show_message_from_socket)
        self.socket.error.connect(self.show_error_from_socket)
        
        
    @property
    def _watcher_file_name(self):
        return "d2mp.pid"
    
    def _start_file_watcher(self):
        self.watcher = QFileSystemWatcher()
        self.watcher_file_path =  join(abspath("."), self._watcher_file_name)
        log.DEBUG("creating watcher file: %s" %(self.watcher_file_path))
        write_to_file(self.watcher_file_path, "Delete this file to shutdown D2MP\n")
        self.watcher.addPath(abspath("."))
        self.watcher.directoryChanged.connect(self._watcher_changed_callback)
    
    def _watcher_changed_callback(self, val):
        if self._watcher_file_name not in os.listdir(val): 
            secs = 3
            self.show_message("Shutdown", "Watcher file was deleted. D2MP will shotdown in %d seconds." %(secs))
            sleep(secs)
            self.exit()
    
    def _create_tray_icon(self):
        self.tray = QSystemTrayIcon(self)
        self.tray.setToolTip("D2Moddin Manager")
        self.tray.setIcon(QIcon(SETTINGS['icon']))
        traymenu = QMenu()
        traymenu.addAction("Restart", self.restart)
        traymenu.addAction("Uninstall", self.uninstall)
        traymenu.addAction("Preferences", UIManager().open_preferences)
        traymenu.addAction("Show mod list", self.show_mod_list)
        traymenu.addSeparator()

        traymenu.addAction("Exit", self.exit)
    
        self.tray.setContextMenu(traymenu)
        self.tray.show()
    
    def restart(self):
        python = sys.executable
        args = set(sys.argv)
        args.add("restart")
        os.execl(python, python, *list(sys.argv))
        self.exit()
    
    def uninstall(self):
        ModManager().delete_mods()
#         ModManager().uninstall_d2mp()
        self.exit()
    
    def exit(self):
        # do some cleanup
        return super(SingleApplication, self).exit()
    
    def show_mod_list(self):
        self.show_message("Mod List", ModManager().mod_names_as_string())
    
    def show_message_from_socket(self, message):
        self.show_message("Server message", message)
        
    def show_error_from_socket(self, message):
        self.show_message("Server error", message, QSystemTrayIcon.Critical)
        
    def show_message_from_mod_manager(self, message):
        self.show_message("ModManager message", message)
        
    def show_error_from_mod_manager(self, message):
        self.show_message("ModManager error", message, QSystemTrayIcon.Critical)
        
    def show_message(self, title, message, icon = QSystemTrayIcon.Information):
        self.tray.showMessage(title, message, icon)
示例#34
0
def select():
    """select folder"""
    fileDialog = QFileDialog(d)
    fileDialog.setWindowTitle('Select Folder')
    folderPath = fileDialog.getExistingDirectory()
    #print folderPath
    fts.append('%s' % folderPath)
    confManager.setValue('common', 'folders', fts)
    confManager.save()


ui.connBtn.connect(ui.connBtn, SIGNAL('clicked()'),
                   lambda: connect(ui.connBtn))
ui.addFolderBtn.clicked.connect(select)

menu = QMenu(m)
es = menu.addAction('ShowConfig')
menu.connect(es, SIGNAL('triggered()'), d, SLOT('show()'))

menu.addSeparator()

ea = menu.addAction("&Exit")
menu.connect(ea, SIGNAL('triggered()'), app, SLOT('quit()'))

t.setContextMenu(menu)

t.show()
t.showMessage('UniFileSyncPop Message', 'This is UniFileSyncUI!!')

sys.exit(app.exec_())
示例#35
0
        pass
    elif (sys.argv[1] != "debug"):
        import wingdbstub

    app = QApplication(sys.argv)
    app.setQuitOnLastWindowClosed(False)
    window = myMainWindow()

    tray = QSystemTrayIcon(QIcon(":/pics/pic24.png"))
    menu = QMenu()
    actionShow = QAction("Show Leopard Flower", menu)
    actionExit = QAction("Exit", menu)
    menu.addAction(actionShow)
    menu.addAction(actionExit)
    tray.setContextMenu(menu)
    tray.show()
    actionShow.triggered.connect(window.show)
    actionExit.triggered.connect(window.realQuit)

    sourcemodel = myModel()
    model = mySortFilterProxyModel()
    model.setSourceModel(sourcemodel)
    model.setDynamicSortFilter(True)

    window.tableView.setSortingEnabled(True)
    window.tableView.setModel(model)
    window.model = model
    window.sourcemodel = sourcemodel

    delegate = CustomDelegate()
    window.tableView.setItemDelegateForColumn(4, delegate)
示例#36
0
class MainWindow(QMainWindow):
    def __init__(self, config):
        super(MainWindow, self).__init__()
        self.config = Config(config)
        db = Database(self.config.getConnectionString())
        db.create()
        self.hosts = Hosts(db)

        # menu used for each host
        self.hostMenu = QMenu()
        self.hostMenu.addAction(QIcon(":/ico/edit.svg"), "Edit", self.editHost)
        self.hostMenu.addAction(QIcon(":/ico/remove.svg"), "Delete", self.deleteHost)
        actions.addActionWithScreenChose(
            self.hostMenu, self.connectFrameless, ":/ico/frameless.svg", "Connect frameless"
        )

        # setup main window
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

        # when top level changed, we changing dock title bar
        self.dockWidgetTileBar = DockWidgetTitleBar()
        self.ui.hostsDock.setTitleBarWidget(self.dockWidgetTileBar)
        self.ui.hostsDock.topLevelChanged.connect(self.dockLevelChanged)

        # set global menu
        self.globalMenu = QMenu()
        self.globalMenu.addAction(QIcon(":/ico/add.svg"), "Add host", self.addHost)
        # disable menu indicator
        self.ui.menu.setStyleSheet("QPushButton::menu-indicator {image: none;}")
        self.positionMenu = QMenu("Dock position")
        self.positionMenu.addAction("Left", lambda: self.setDockPosition(Qt.LeftDockWidgetArea))
        self.positionMenu.addAction("Right", lambda: self.setDockPosition(Qt.RightDockWidgetArea))
        self.positionMenu.addAction("Float", self.setDockFloat)
        self.globalMenu.addMenu(self.positionMenu)
        self.globalMenu.addAction("Change tray icon visibility", self.changeTrayIconVisibility)
        self.globalMenu.addAction("Quit", self.close)
        self.ui.menu.setMenu(self.globalMenu)

        # set events on hosts list
        self.ui.hostsList.itemDoubleClicked.connect(self.slotConnectHost)
        self.ui.hostsList.itemClicked.connect(self.slotShowHost)
        self.ui.hostsList.customContextMenuRequested.connect(self.slotShowHostContextMenu)

        # set tab widget
        self.tabWidget = MyTabWidget()
        self.setCentralWidget(self.tabWidget)

        # set tray icon
        self.tray = QSystemTrayIcon(QIcon(":/ico/myrdp.svg"))
        self.tray.activated.connect(self.trayActivated)

        self.trayMenu = QMenu()
        self.trayMenu.addAction("Hide tray icon", self.changeTrayIconVisibility)
        self.trayMenu.addAction("Quit", self.close)

        self.tray.setContextMenu(self.trayMenu)

        # host list
        self.ui.filter.textChanged.connect(self.setHostList)
        self.setHostList()
        self.restoreSettings()

    def trayActivated(self, reason):
        if reason != QSystemTrayIcon.Trigger:
            return
        if self.isVisible():
            self.hide()
        else:
            self.show()
            self.activateWindow()

    def changeTrayIconVisibility(self):
        if self.tray.isVisible():
            self.tray.hide()
            if not self.isVisible():
                self.show()
        else:
            self.tray.show()

    def setDockPosition(self, dockWidgetArea):
        if self.ui.hostsDock.isFloating():
            self.ui.hostsDock.setFloating(False)
        self.addDockWidget(dockWidgetArea, self.ui.hostsDock)

    def setDockFloat(self):
        if self.ui.hostsDock.isFloating():
            return
        # default title bar must be set before is float because sometimes window make strange crash
        self.ui.hostsDock.setTitleBarWidget(None)
        self.ui.hostsDock.setFloating(True)

    def dockLevelChanged(self, isFloating):
        if isFloating:
            # changing title bar widget if is not none, probably true will be only once on start with saved float state
            if self.ui.hostsDock.titleBarWidget():
                self.ui.hostsDock.setTitleBarWidget(None)
        else:
            self.ui.hostsDock.setTitleBarWidget(self.dockWidgetTileBar)

    def showFramelessWidget(self):
        self.t.show()
        self.t.setGeometry(self.frameGeometry())

    def getCurrentHostListItemName(self):
        return self.ui.hostsList.currentItem().text()

    def findHostItemByName(self, name):
        result = self.ui.hostsList.findItems(name, Qt.MatchExactly)
        resultLen = len(result)
        if resultLen != 1:  # should be only one host
            logging.error("Host not found. Got %d results" % resultLen)
        return result[0]

    def slotShowHostContextMenu(self, pos):
        """ slot needed to show menu in proper position, or i'm doing something wrong
        """
        self.hostMenu.exec_(self.ui.hostsList.mapToGlobal(pos))

    def addHost(self):
        hostDialog = HostConfigDialog(self.hosts)
        resp = hostDialog.add()
        if resp["code"]:
            self.setHostList()
        hostName = resp.get("name")
        if hostName:
            hostItem = self.findHostItemByName(hostName)
            self.slotConnectHost(hostItem)

    def editHost(self):
        hostDialog = HostConfigDialog(self.hosts)
        resp = hostDialog.edit(self.getCurrentHostListItemName())
        if resp["code"]:
            self.setHostList()

    def deleteHost(self):
        self.hosts.delete(self.getCurrentHostListItemName())
        self.setHostList()

    def connectFrameless(self, screenIndex=None):
        self.connectHost(self.getCurrentHostListItemName(), frameless=True, screenIndex=screenIndex)

    # Fix to release keyboard from QX11EmbedContainer, when we leave widget through wm border
    def leaveEvent(self, event):
        keyG = QWidget.keyboardGrabber()
        if keyG is not None:
            keyG.releaseKeyboard()
        event.accept()  # needed?

    def setHostList(self):
        """ set hosts list in list view """
        self.ui.hostsList.clear()
        self.ui.hostsList.addItems(self.hosts.getFilteredHostsNames(self.ui.filter.text()))

    def slotShowHost(self, item):
        # on one click we activating tab and showing options
        self.tabWidget.activateTab(item)

    def slotConnectHost(self, item):
        self.connectHost(unicode(item.text()))

    def connectHost(self, hostId, frameless=False, screenIndex=None):
        hostId = unicode(hostId)  # sometimes hostId comes as QString
        tabPage = self.tabWidget.createTab(hostId)
        tabPage.reconnectionNeeded.connect(self.connectHost)

        if frameless:
            self.tabWidget.detachFrameless(tabPage, screenIndex)

        execCmd, opts = self.getCmd(tabPage, hostId)
        ProcessManager.start(hostId, tabPage, execCmd, opts)

    def getCmd(self, tabPage, hostName):
        host = self.hosts.get(hostName)

        # set tabPage widget
        width, height = tabPage.setSizeAndGetCurrent()
        # 1et widget winId to embed rdesktop
        winId = tabPage.x11.winId()

        # set remote desktop client, at this time works only with freerdp
        remoteClientType, remoteClientOptions = self.config.getRdpClient()
        remoteClient = ClientFactory(remoteClientType, **remoteClientOptions)
        remoteClient.setWindowParameters(winId, width, height)
        remoteClient.setUserAndPassword(host.user, host.password)
        remoteClient.setAddress(host.address)
        return remoteClient.getComposedCommand()

    def saveSettings(self):
        settings = QSettings("MyRDP")
        settings.setValue("geometry", self.saveGeometry())
        settings.setValue("windowState", self.saveState())
        settings.setValue("trayIconVisibility", self.tray.isVisible())

    def restoreSettings(self):
        settings = QSettings("MyRDP")

        try:
            self.restoreGeometry(settings.value("geometry").toByteArray())
            self.restoreState(settings.value("windowState").toByteArray())
        except Exception:
            logging.debug("No settings to restore")

        # restore tray icon state
        trayIconVisibility = settings.value("trayIconVisibility").toBool()
        self.tray.setVisible(trayIconVisibility)

    def closeEvent(self, event):
        if not ProcessManager.hasActiveProcess:
            self.saveSettings()
            return

        msgBox = QMessageBox(self, text="Are you sure do you want to quit?")
        msgBox.setWindowTitle("Exit confirmation")
        msgBox.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
        ret = msgBox.exec_()
        if ret == QMessageBox.Cancel:
            event.ignore()
            return

        self.saveSettings()
        ProcessManager.killemall()
        event.accept()
示例#37
0
class MainWindow(QMainWindow):
    groups = dict()
    typeQListWidgetHeader = 1000
    showHostsInGroups = False
    currentGroupName = None  # used to simple detect currently selected group to show menu

    def __init__(self):
        super(MainWindow, self).__init__()
        self.config = Config()
        self.db = Database(self.config.getConnectionString())

        cryptoKey = self.getCryptoKey()
        self.hosts = Hosts(self.db, cryptoKey)

        # menu used for each host
        self.hostMenu = QMenu()
        self.editAction = QAction(QIcon(':/ico/edit.svg'), "Edit",
                                  self.hostMenu)
        self.editAction.triggered.connect(self.editHost)
        self.hostMenu.addAction(self.editAction)

        # menu used for headers of groups
        self.groupsHeaderMenu = QMenu()
        self.editGroupAction = QAction(QIcon(':/ico/edit.svg'), "Edit group",
                                       self.groupsHeaderMenu)
        self.editGroupAction.triggered.connect(self.editGroup)
        self.deleteGroupAction = QAction(QIcon(':/ico/remove.svg'),
                                         "Delete group", self.groupsHeaderMenu)
        self.deleteGroupAction.triggered.connect(self.deleteGroup)
        self.groupsHeaderMenu.addAction(self.editGroupAction)
        self.groupsHeaderMenu.addAction(self.deleteGroupAction)

        self.duplicateAction = QAction(QIcon(':/ico/copy.svg'), "Duplicate",
                                       self.hostMenu)
        self.duplicateAction.triggered.connect(self.duplicateHost)
        self.hostMenu.addAction(self.duplicateAction)

        # todo: confirm for delete action
        self.deleteAction = QAction(QIcon(':/ico/remove.svg'), "Delete",
                                    self.hostMenu)
        self.deleteAction.triggered.connect(self.deleteHost)
        self.hostMenu.addAction(self.deleteAction)

        self.connectFramelessMenu = actions.generateScreenChoseMenu(
            self.hostMenu, self.connectFrameless, ':/ico/frameless.svg',
            "Connect frameless")
        self.hostMenu.addMenu(self.connectFramelessMenu)

        self.assignGroupAction = QAction("Assign group", self.hostMenu)
        self.assignGroupAction.triggered.connect(self.assignGroup)
        self.hostMenu.addAction(self.assignGroupAction)

        # setup main window
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

        # when top level changed, we changing dock title bar
        self.dockWidgetTileBar = DockWidgetTitleBar()
        self.ui.hostsDock.setTitleBarWidget(self.dockWidgetTileBar)
        self.ui.hostsDock.topLevelChanged.connect(self.dockLevelChanged)

        # set global menu
        self.globalMenu = QMenu()
        self.globalMenu.addAction(QIcon(':/ico/add.svg'), 'Add host',
                                  self.addHost)

        # groups menu
        self.groupsMenu = QMenu("Groups")
        self.groupsMenu.aboutToShow.connect(self.setGroupsMenu)
        self.globalMenu.addMenu(self.groupsMenu)

        # disable menu indicator
        self.ui.menu.setStyleSheet(
            "QPushButton::menu-indicator {image: none;}")
        self.positionMenu = QMenu("Dock position")
        self.positionMenu.addAction(
            "Left", lambda: self.setDockPosition(Qt.LeftDockWidgetArea))
        self.positionMenu.addAction(
            "Right", lambda: self.setDockPosition(Qt.RightDockWidgetArea))
        self.positionMenu.addAction("Float", self.setDockFloat)
        self.globalMenu.addMenu(self.positionMenu)
        self.globalMenu.addAction('Change tray icon visibility',
                                  self.changeTrayIconVisibility)
        self.globalMenu.addAction('Settings', self.showSettings)
        self.globalMenu.addAction('Quit', self.close)
        self.ui.menu.setMenu(self.globalMenu)

        # set events on hosts list
        self.ui.hostsList.itemDoubleClicked.connect(self.slotConnectHost)
        self.ui.hostsList.itemClicked.connect(self.slotShowHost)
        self.ui.hostsList.customContextMenuRequested.connect(
            self.slotShowHostContextMenu)

        # set tab widget
        self.tabWidget = MyTabWidget()
        self.setCentralWidget(self.tabWidget)
        self.tabWidget.setContextMenuPolicy(Qt.CustomContextMenu)
        self.tabWidget.customContextMenuRequested.connect(
            self.showCentralWidgetContextMenu)

        # set tray icon
        self.tray = QSystemTrayIcon(QIcon(":/ico/myrdp.svg"))
        self.tray.activated.connect(self.trayActivated)

        self.trayMenu = QMenu()
        self.trayMenu.addAction("Hide tray icon",
                                self.changeTrayIconVisibility)
        self.connectHostMenuTray = ConnectHostMenu(self.hosts)
        self.connectHostMenuTray.triggered.connect(
            self.connectHostFromTrayMenu)
        self.trayMenu.addMenu(self.connectHostMenuTray)
        self.trayMenu.addAction("Quit", self.close)

        self.tray.setContextMenu(self.trayMenu)
        self.restoreSettings()
        # host list
        self.ui.filter.textChanged.connect(self.setHostList)
        self.setHostList()

    def getCryptoKey(self, passphrase=None):
        try:
            return self.config.getPrivateKey(passphrase)
        except ValueError:
            passwordDialog = PasswordDialog()
            retCode = passwordDialog.exec_()
            if retCode == QtGui.QDialog.Accepted:
                return self.getCryptoKey(passwordDialog.getPassword())
            else:
                raise SystemError("Password required")

    def showSettings(self):
        settingsWidget = self.findChild(QWidget, "settings")
        if settingsWidget is None:
            self.settingsWidget = SettingsPage()
            self.settingsWidget.setObjectName("settings")
            self.tabWidget.insertTab(0, self.settingsWidget,
                                     QIcon(":/ico/settings.svg"), 'Settings')

        index = self.tabWidget.indexOf(self.settingsWidget)
        self.tabWidget.setCurrentIndex(index)

    def connectHostFromMenu(self, action):
        self.connectHost(unicode(action.text()))

    def connectHostFromTrayMenu(self, action):
        tabPage = self.connectHost(unicode(action.text()))
        if not self.isVisible():
            self.tabWidget.setDetached(True, tabPage)

    def trayActivated(self, reason):
        if reason != QSystemTrayIcon.Trigger:
            return
        if self.isVisible():
            self.hide()
        else:
            self.show()
            self.activateWindow()

    def changeTrayIconVisibility(self):
        if self.tray.isVisible():
            self.tray.hide()
            if not self.isVisible():
                self.show()
        else:
            self.tray.show()

    def refreshGroups(self):
        groupList = self.hosts.getGroupsList()
        for group in groupList:
            if group not in self.groups:
                # add new groups as visible
                self.groups[group] = True

        # remove not existing groups
        keysToDelete = set(self.groups.keys()) - set(groupList)
        for key in keysToDelete:
            self.groups.pop(key)

    def assignGroup(self):
        groups = self.hosts.getGroupsList()
        assignGroupDialog = AssignGroupDialog(groups)
        groupToAssign = assignGroupDialog.assign()
        if groupToAssign is not False:  # None could be used to unassign the group
            groupToAssign = None if groupToAssign.isEmpty() else unicode(
                groupToAssign)
            for hostName in self.getSelectedHosts():
                self.hosts.assignGroup(hostName, groupToAssign)
            self.db.tryCommit()
            self.setHostList()

    def setGroupsMenu(self):
        self.groupsMenu.clear()
        addGroupAction = self.groupsMenu.addAction('Add group')
        addGroupAction.triggered.connect(self.addGroup)

        deleteGroupAction = self.groupsMenu.addAction('Delete group')
        deleteGroupAction.triggered.connect(self.showDeleteGroupDialog)

        showHostsInGroupsAction = self.groupsMenu.addAction(
            'Show host list in groups')
        showHostsInGroupsAction.triggered.connect(self.changeHostListView)
        showHostsInGroupsAction.setCheckable(True)
        showHostsInGroupsAction.setChecked(self.showHostsInGroups)

        self.groupsMenu.addSeparator()
        for group, checked in self.groups.items():
            action = QAction(group, self.groupsMenu)
            action.setCheckable(True)
            action.setChecked(checked)
            action.triggered.connect(self.groupsVisibilityChanged)
            self.groupsMenu.addAction(action)

    def addGroup(self):
        groupConfigDialog = GroupConfigDialog(self.hosts.groups)
        resp = groupConfigDialog.add()
        self._processHostSubmit(resp)

    def groupsVisibilityChanged(self, checked):
        currentGroup = unicode(self.sender().text())
        self.groups[currentGroup] = checked
        self.setHostList()

    def setDockPosition(self, dockWidgetArea):
        if self.ui.hostsDock.isFloating():
            self.ui.hostsDock.setFloating(False)
        self.addDockWidget(dockWidgetArea, self.ui.hostsDock)

    def setDockFloat(self):
        if self.ui.hostsDock.isFloating():
            return
        # default title bar must be set before is float because sometimes window make strange crash
        self.ui.hostsDock.setTitleBarWidget(None)
        self.ui.hostsDock.setFloating(True)

    def dockLevelChanged(self, isFloating):
        if isFloating:
            # changing title bar widget if is not none, probably true will be only once on start with saved float state
            if self.ui.hostsDock.titleBarWidget():
                self.ui.hostsDock.setTitleBarWidget(None)
        else:
            self.ui.hostsDock.setTitleBarWidget(self.dockWidgetTileBar)

    def showFramelessWidget(self):
        self.t.show()
        self.t.setGeometry(self.frameGeometry())

    def getCurrentHostListItemName(self):
        return self.ui.hostsList.currentItem().text()

    def getSelectedHosts(self):
        return [host.text() for host in self.ui.hostsList.selectedItems()]

    def findHostItemByName(self, name):
        result = self.ui.hostsList.findItems(name, Qt.MatchExactly)
        resultLen = len(result)
        if resultLen != 1:  # should be only one host
            logger.error("Host not found. Got %d results" % resultLen)
        return result[0]

    def showCentralWidgetContextMenu(self, pos):
        menu = QMenu()
        title = self.ui.hostsDock.windowTitle()

        hostsDockAction = menu.addAction(title)
        hostsDockAction.setCheckable(True)
        hostsDockAction.setChecked(self.ui.hostsDock.isVisible())
        hostsDockAction.triggered.connect(self.changeHostsDockWidgetVisibility)

        hostsDockAction = menu.addAction("Tray icon")
        hostsDockAction.setCheckable(True)
        hostsDockAction.setChecked(self.tray.isVisible())
        hostsDockAction.triggered.connect(self.changeTrayIconVisibility)

        connectHostMenuTray = ConnectHostMenu(self.hosts, "Connect")
        connectHostMenuTray.triggered.connect(self.connectHostFromMenu)
        menu.addMenu(connectHostMenuTray)

        menu.exec_(self.tabWidget.mapToGlobal(pos))

    def changeHostListView(self, checked):
        self.showHostsInGroups = checked
        self.setHostList()

    def changeHostsDockWidgetVisibility(self):
        isVisible = self.ui.hostsDock.isVisible()
        self.ui.hostsDock.setVisible(not isVisible)

    def isHostListHeader(self, item):
        if not item or item.type() == self.typeQListWidgetHeader:
            return True
        return False

    def slotShowHostContextMenu(self, pos):
        def changeMenusVisibility(isEnabled):
            self.connectFramelessMenu.setEnabled(isEnabled)
            self.editAction.setEnabled(isEnabled)
            self.duplicateAction.setEnabled(isEnabled)

        # ignore context menu for group headers
        item = self.ui.hostsList.itemAt(pos)

        if self.isHostListHeader(item):
            item = self.ui.hostsList.itemAt(pos)
            widgetItem = self.ui.hostsList.itemWidget(item)
            if widgetItem:
                self.currentGroupName = widgetItem.text()  # yea I'm so dirty
                if self.currentGroupName != unassignedGroupName:
                    self.groupsHeaderMenu.exec_(
                        self.ui.hostsList.mapToGlobal(pos))
            return

        if len(self.ui.hostsList.selectedItems()) == 1:  # single menu
            changeMenusVisibility(True)
        else:
            changeMenusVisibility(False)

        self.hostMenu.exec_(self.ui.hostsList.mapToGlobal(pos))

    def _processHostSubmit(self, resp):
        if resp["code"]:
            self.setHostList()
        hostName = resp.get("name")
        if hostName:
            hostItem = self.findHostItemByName(hostName)
            self.slotConnectHost(hostItem)

    def addHost(self):
        hostDialog = HostConfigDialog(self.hosts)
        self._processHostSubmit(hostDialog.add())

    def editHost(self):
        hostDialog = HostConfigDialog(self.hosts)
        resp = hostDialog.edit(self.getCurrentHostListItemName())
        self._processHostSubmit(resp)

    def editGroup(self):
        groupConfigDialog = GroupConfigDialog(self.hosts.groups)
        resp = groupConfigDialog.edit(self.currentGroupName)
        self._processHostSubmit(resp)

    def deleteGroup(self):
        retCode = self.showOkCancelMessageBox(
            "Do you want to remove selected group? All assigned hosts "
            "to this group will be unassigned.", "Confirmation")
        if retCode == QMessageBox.Cancel:
            return

        self.hosts.deleteGroup(self.currentGroupName)
        self.setHostList()

    def showDeleteGroupDialog(self):
        deleteGroupDialog = DeleteGroupDialog(self.hosts)
        deleteGroupDialog.deleteGroup()
        self.setHostList()

    def duplicateHost(self):
        hostDialog = HostConfigDialog(self.hosts)
        resp = hostDialog.duplicate(self.getCurrentHostListItemName())
        self._processHostSubmit(resp)

    def deleteHost(self):
        retCode = self.showOkCancelMessageBox(
            "Do you want to remove selected hosts?", "Confirmation")
        if retCode == QMessageBox.Cancel:
            return

        for host in self.getSelectedHosts():
            self.hosts.delete(host)
        self.setHostList()

    def connectFrameless(self, screenIndex=None):
        self.connectHost(self.getCurrentHostListItemName(),
                         frameless=True,
                         screenIndex=screenIndex)

    # Fix to release keyboard from QX11EmbedContainer, when we leave widget through wm border
    def leaveEvent(self, event):
        keyG = QWidget.keyboardGrabber()
        if keyG is not None:
            keyG.releaseKeyboard()
        event.accept()  # needed?

    def setHostList(self):
        """ set hosts list in list view """
        self.ui.hostsList.clear()
        self.refreshGroups()
        hostFilter = self.ui.filter.text()
        if self.showHostsInGroups:
            self.showHostListInGroups(hostFilter)
        else:
            self.showHostList(hostFilter)

    def showHostList(self, hostFilter):
        groupFilter = [
            group for group, visibility in self.groups.items() if visibility
        ]
        hosts = self.hosts.getHostsListByHostNameAndGroup(
            hostFilter, groupFilter)
        self.ui.hostsList.addItems(hosts)

    def showHostListInGroups(self, hostFilter):
        hosts = self.hosts.getGroupedHostNames(hostFilter)
        for group, hostsList in hosts.items():
            if self.groups.get(group, True):
                if group is None:
                    group = unassignedGroupName
                groupHeader = QtGui.QListWidgetItem(
                    type=self.typeQListWidgetHeader)
                groupLabel = QtGui.QLabel(unicode(group))
                groupLabel.setProperty('class', 'group-title')
                self.ui.hostsList.addItem(groupHeader)
                self.ui.hostsList.setItemWidget(groupHeader, groupLabel)
                self.ui.hostsList.addItems(hostsList)

    def slotShowHost(self, item):
        # on one click we activating tab and showing options
        self.tabWidget.activateTab(item)

    def slotConnectHost(self, item):
        if self.isHostListHeader(item):
            return
        self.connectHost(unicode(item.text()))

    def connectHost(self, hostId, frameless=False, screenIndex=None):
        hostId = unicode(hostId)  # sometimes hostId comes as QString
        tabPage = self.tabWidget.createTab(hostId)
        tabPage.reconnectionNeeded.connect(self.connectHost)

        if frameless:
            self.tabWidget.detachFrameless(tabPage, screenIndex)

        try:
            execCmd, opts = self.getCmd(tabPage, hostId)
        except LookupError:
            logger.error(u"Host {} not found.".format(hostId))
            return

        ProcessManager.start(hostId, tabPage, execCmd, opts)
        return tabPage

    def getCmd(self, tabPage, hostName):
        host = self.hosts.get(hostName)

        # set tabPage widget
        width, height = tabPage.setSizeAndGetCurrent()
        # 1et widget winId to embed rdesktop
        winId = tabPage.x11.winId()

        # set remote desktop client, at this time works only with freerdp
        remoteClientType, remoteClientOptions = self.config.getRdpClient()
        remoteClient = ClientFactory(remoteClientType, **remoteClientOptions)
        remoteClient.setWindowParameters(winId, width, height)
        remoteClient.setUserAndPassword(host.user, host.password)
        remoteClient.setAddress(host.address)
        return remoteClient.getComposedCommand()

    def saveSettings(self):
        self.config.setValue("geometry", self.saveGeometry())
        self.config.setValue("windowState", self.saveState())
        self.config.setValue('trayIconVisibility', self.tray.isVisible())
        self.config.setValue('mainWindowVisibility', self.isVisible())
        self.config.setValue('groups', self.groups)
        self.config.setValue('showHostsInGroups', self.showHostsInGroups)

    def restoreSettings(self):
        try:
            self.restoreGeometry(
                self.config.getValue("geometry").toByteArray())
            self.restoreState(
                self.config.getValue("windowState").toByteArray())
        except Exception:
            logger.debug("No settings to restore")

        # restore tray icon state
        trayIconVisibility = self.config.getValue('trayIconVisibility',
                                                  "true").toBool()
        self.tray.setVisible(trayIconVisibility)

        self.showHostsInGroups = self.config.getValue('showHostsInGroups',
                                                      'false').toBool()

        if self.tray.isVisible():
            mainWindowVisibility = self.config.getValue(
                'mainWindowVisibility', "true").toBool()
            self.setVisible(mainWindowVisibility)
        else:  # it tray icon is not visible, always show main window
            self.show()

        self.groups = {
            unicode(k): v
            for k, v in self.config.getValue('groups',
                                             {}).toPyObject().items()
        }

    def closeEvent(self, event):
        if not ProcessManager.hasActiveProcess:
            self.saveSettings()
            QCoreApplication.exit()
            return

        ret = self.showOkCancelMessageBox("Are you sure do you want to quit?",
                                          "Exit confirmation")
        if ret == QMessageBox.Cancel:
            event.ignore()
            return

        self.saveSettings()
        ProcessManager.killemall()
        event.accept()
        QCoreApplication.exit()

    def showOkCancelMessageBox(self, messageBoxText, windowTitle):
        msgBox = QMessageBox(self, text=messageBoxText)
        msgBox.setWindowTitle(windowTitle)
        msgBox.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
        msgBox.setIcon(QMessageBox.Question)
        return msgBox.exec_()
示例#38
0
class Example(QtGui.QMainWindow):
    def __init__(self):
        super(Example, self).__init__()

        self.path = sys.path[0]
        f = open("%s/ACCESS_KEY" % self.path, "r")
        f1 = open("%s/ACCESS_SECRET" % self.path, "r")
        f2 = open("%s/user_info" % self.path)
        self.user_name = f2.readline().strip("\n")
        self.user_id = f2.readline().strip("\n")
        self.a = f.readline().strip("\n")
        self.b = f1.readline().strip("\n")
        f.close()
        f1.close()
        f2.close()
        self.initUI()

    def initUI(self):

        self.icon = QSystemTrayIcon()
        self.icon.isSystemTrayAvailable()
        self.icon.setIcon(QtGui.QIcon("%s/me.jpg" % self.path))
        self.icon.setToolTip("dubbleclick untuk maximize")
        self.icon.show()
        self.icon.activated.connect(self.activate)
        self.setWindowFlags(QtCore.Qt.FramelessWindowHint)
        self.setAttribute(QtCore.Qt.WA_TranslucentBackground)
        self.setGeometry(150, 150, 500, 200)
        frame = QtGui.QFrame(parent=self)
        frame.setStyleSheet("QFrame {background: rgba(0,0,0,50%)}")
        box = QtGui.QHBoxLayout()

        self.edit = QtGui.QLineEdit()
        self.edit.setStyleSheet(
            "background: rgba(0,0,0,100%); " " font-weight : bold;" "color:  rgb(250,250,250);" "border:5px solid "
        )
        self.edit.setToolTip("Tolong  <b>Massukan tweet Anda di sini </b> ")
        self.edit.returnPressed.connect(self.returnPressed)
        box.addWidget(self.edit)

        frame.setLayout(box)

        qbtn1 = QtGui.QPushButton("keluar", self)
        qbtn1.clicked.connect(self.close)
        qbtn1.setStyleSheet(
            "background: rgba(0,0,0,100%); " " font-weight : bold;" "color:  rgb(250,250,250);" "border:5px solid "
        )
        box.addWidget(qbtn1)
        self.statusBar().setStyleSheet(
            "background: rgba(0,0,0,100%);" " font-weight : bold;" "color:  rgb(250,250,250)"
        )
        self.statusBar().showMessage("Tekan enter untuk mengirim twitter, ESC untuk minimize")

        self.setCentralWidget(frame)
        self.setWindowIcon(QtGui.QIcon("%s/me.jpg" % self.path))

        self.setWindowTitle("Twitter Client With PyQt4")
        self.center()
        self.show()
        self.twitter_auth()

    def twitter_auth(self):

        CONSUMER_KEY = "gYMpKX6YWDP5rBwvCcriQ"
        CONSUMER_SECRET = "ulK4WA6gtB5FekyPYRrOXVCxeqvwP66leFfNq5DY"
        ACCESS_KEY = self.a
        ACCESS_SECRET = self.b
        self.auth = tweepy.OAuthHandler(CONSUMER_KEY, CONSUMER_SECRET)
        self.auth.set_access_token(ACCESS_KEY, ACCESS_SECRET)

    def keyPressEvent(self, e):
        if e.key() == QtCore.Qt.Key_Escape:
            print "Escape wass pressed "
            self.icon.show()

            self.hide()

    def activate(self, reason):
        print reason
        if reason == 2:
            self.show()

    def center(self):

        qr = self.frameGeometry()
        cp = QtGui.QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())

    def returnPressed(self):
        path = sys.path[0]
        tweet = self.edit.text()
        api = tweepy.API(self.auth)
        self.statusBar().showMessage("Mengirim . ..  ")
        api.update_status(tweet)
        self.statusBar().showMessage("Twitter Anda terkirim ! ")
        n = pynotify.Notification(
            " @ %s " % self.user_name, "twitter Anda terkirim ", "%s/%s.jpg" % (path, self.user_id)
        )
        n.set_hint("x", 200)
        n.set_hint("y", 400)
        pynotify.init("n")
        n.show()
        self.statusBar().showMessage("Tekan enter untuk mengirim dan tekan ESC untuk minimize ")
        self.edit.clear()
示例#39
0
    name, email = author.rsplit(" ", 1)
    aboutData.addAuthor(ki18n(name), ki18n(""), email.strip("<>"), "")

KCmdLineArgs.init(sys.argv, aboutData)
app = KApplication()

import smart

ctrl = smart.init()

mainWindow = KMainWindow()
smart_icon = QIcon(getPixmap("smart"))
mainWindow.setWindowIcon(smart_icon)
sysTray = QSystemTrayIcon(smart_icon, None)
smart_image = getPixmap("smart").toImage()
aboutData.setProgramLogo(QVariant(smart_image))

menu = QMenu(None)
menu.addAction(KIcon("view-refresh"), "Check for updates", smart_update)
menu.addAction(smart_icon, "Launch Smart", smart_gui)
menu.addSeparator()
menu.addAction(KIcon("help-about"), "About", show_about)
menu.addAction(KIcon("application-exit"), "Quit", exit_applet)
sysTray.setContextMenu(menu)

sysTray.show()

app.exec_()

# vim:ts=4:sw=4:et
示例#40
0
class MainWindow(base_class, ui_class):
    implements(IObserver)

    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.saved_account_state = None

        notification_center = NotificationCenter()
        notification_center.add_observer(self, name='SIPApplicationWillStart')
        notification_center.add_observer(self, name='SIPApplicationDidStart')
        notification_center.add_observer(self, name='SIPAccountGotMessageSummary')
        notification_center.add_observer(self, name='SIPAccountGotPendingWatcher')
        notification_center.add_observer(self, name='BlinkSessionNewOutgoing')
        notification_center.add_observer(self, name='BlinkSessionDidReinitializeForOutgoing')
        notification_center.add_observer(self, name='BlinkFileTransferNewIncoming')
        notification_center.add_observer(self, name='BlinkFileTransferNewOutgoing')
        notification_center.add_observer(self, name='DocumentSharingFileTransferCompleted')
        notification_center.add_observer(self, sender=AccountManager())

        icon_manager = IconManager()

        self.pending_watcher_dialogs = []

        self.mwi_icons = [QIcon(Resources.get('icons/mwi-%d.png' % i)) for i in xrange(0, 11)]
        self.mwi_icons.append(QIcon(Resources.get('icons/mwi-many.png')))

        with Resources.directory:
            self.setupUi()

        self.setWindowTitle('Blink')
        self.setWindowIconText('Blink')

        geometry = QSettings().value("main_window/geometry")
        if geometry:
            self.restoreGeometry(geometry)

        self.default_icon_path = Resources.get('icons/default-avatar.png')
        self.default_icon = QIcon(self.default_icon_path)
        self.last_icon_directory = Path('~').normalized
        self.set_user_icon(icon_manager.get('avatar'))

        self.active_sessions_label.hide()
        self.enable_call_buttons(False)
        self.conference_button.setEnabled(False)
        self.hangup_all_button.setEnabled(False)
        self.sip_server_settings_action.setEnabled(False)
        self.search_for_people_action.setEnabled(False)
        self.history_on_server_action.setEnabled(False)
        self.main_view.setCurrentWidget(self.contacts_panel)
        self.contacts_view.setCurrentWidget(self.contact_list_panel)
        self.search_view.setCurrentWidget(self.search_list_panel)

        # System tray
        if QSystemTrayIcon.isSystemTrayAvailable():
            self.system_tray_icon = QSystemTrayIcon(QIcon(Resources.get('icons/blink.png')), self)
            self.system_tray_icon.activated.connect(self._SH_SystemTrayIconActivated)
            menu = QMenu(self)
            menu.addAction(QAction("Show", self, triggered=self._AH_SystemTrayShowWindow))
            menu.addAction(QAction(QIcon(Resources.get('icons/application-exit.png')), "Quit", self, triggered=self._AH_QuitActionTriggered))
            self.system_tray_icon.setContextMenu(menu)
            self.system_tray_icon.show()
        else:
            self.system_tray_icon = None

        # Accounts
        self.account_model = AccountModel(self)
        self.enabled_account_model = ActiveAccountModel(self.account_model, self)
        self.server_tools_account_model = ServerToolsAccountModel(self.account_model, self)
        self.identity.setModel(self.enabled_account_model)

        # Contacts
        self.contact_model = ContactModel(self)
        self.contact_search_model = ContactSearchModel(self.contact_model, self)
        self.contact_list.setModel(self.contact_model)
        self.search_list.setModel(self.contact_search_model)

        # Sessions (audio)
        self.session_model = AudioSessionModel(self)
        self.session_list.setModel(self.session_model)
        self.session_list.selectionModel().selectionChanged.connect(self._SH_SessionListSelectionChanged)

        # History
        self.history_manager = HistoryManager()

        # Windows, dialogs and panels
        self.about_panel = AboutPanel(self)
        self.conference_dialog = ConferenceDialog(self)
        self.contact_editor_dialog = ContactEditorDialog(self)
        self.google_contacts_dialog = GoogleContactsDialog(self)
        self.filetransfer_window = FileTransferWindow()
        self.preferences_window = PreferencesWindow(self.account_model, None)
        self.server_tools_window = ServerToolsWindow(self.server_tools_account_model, None)

        self.documents_window = DocumentsWindow()

        # Signals
        self.account_state.stateChanged.connect(self._SH_AccountStateChanged)
        self.account_state.clicked.connect(self._SH_AccountStateClicked)
        self.activity_note.editingFinished.connect(self._SH_ActivityNoteEditingFinished)
        self.add_contact_button.clicked.connect(self._SH_AddContactButtonClicked)
        self.add_search_contact_button.clicked.connect(self._SH_AddContactButtonClicked)
        self.audio_call_button.clicked.connect(self._SH_AudioCallButtonClicked)
        self.video_call_button.clicked.connect(self._SH_VideoCallButtonClicked)
        self.chat_session_button.clicked.connect(self._SH_ChatSessionButtonClicked)
        self.share_document_button.clicked.connect(self._SH_ShareDocumentButtonClicked)
        self.back_to_contacts_button.clicked.connect(self.search_box.clear) # this can be set in designer -Dan
        self.conference_button.makeConference.connect(self._SH_MakeConference)
        self.conference_button.breakConference.connect(self._SH_BreakConference)

        self.contact_list.selectionModel().selectionChanged.connect(self._SH_ContactListSelectionChanged)
        self.contact_model.itemsAdded.connect(self._SH_ContactModelAddedItems)
        self.contact_model.itemsRemoved.connect(self._SH_ContactModelRemovedItems)

        self.display_name.editingFinished.connect(self._SH_DisplayNameEditingFinished)
        self.hangup_all_button.clicked.connect(self._SH_HangupAllButtonClicked)

        self.identity.activated[int].connect(self._SH_IdentityChanged)
        self.identity.currentIndexChanged[int].connect(self._SH_IdentityCurrentIndexChanged)

        self.mute_button.clicked.connect(self._SH_MuteButtonClicked)

        self.search_box.textChanged.connect(self._SH_SearchBoxTextChanged)
        self.search_box.returnPressed.connect(self._SH_SearchBoxReturnPressed)
        self.search_box.shortcut.activated.connect(self.search_box.setFocus)

        self.search_list.selectionModel().selectionChanged.connect(self._SH_SearchListSelectionChanged)

        self.server_tools_account_model.rowsInserted.connect(self._SH_ServerToolsAccountModelChanged)
        self.server_tools_account_model.rowsRemoved.connect(self._SH_ServerToolsAccountModelChanged)

        self.session_model.sessionAdded.connect(self._SH_AudioSessionModelAddedSession)
        self.session_model.sessionRemoved.connect(self._SH_AudioSessionModelRemovedSession)
        self.session_model.structureChanged.connect(self._SH_AudioSessionModelChangedStructure)

        self.silent_button.clicked.connect(self._SH_SilentButtonClicked)
        self.switch_view_button.viewChanged.connect(self._SH_SwitchViewButtonChangedView)

        # Blink menu actions
        self.about_action.triggered.connect(self.about_panel.show)
        self.add_account_action.triggered.connect(self.preferences_window.show_add_account_dialog)
        self.manage_accounts_action.triggered.connect(self.preferences_window.show_for_accounts)
        self.help_action.triggered.connect(partial(QDesktopServices.openUrl, QUrl(u'http://icanblink.com/help-qt.phtml')))
        self.preferences_action.triggered.connect(self.preferences_window.show)
        self.auto_accept_chat_action.triggered.connect(self._AH_AutoAcceptChatActionTriggered)
        self.received_messages_sound_action.triggered.connect(self._AH_ReceivedMessagesSoundActionTriggered)
        self.answering_machine_action.triggered.connect(self._AH_EnableAnsweringMachineActionTriggered)
        self.release_notes_action.triggered.connect(partial(QDesktopServices.openUrl, QUrl(u'http://icanblink.com/changelog-qt.phtml')))
        self.quit_action.triggered.connect(self._AH_QuitActionTriggered)

        # Call menu actions
        self.redial_action.triggered.connect(self._AH_RedialActionTriggered)
        self.join_conference_action.triggered.connect(self.conference_dialog.show)
        self.history_menu.aboutToShow.connect(self._SH_HistoryMenuAboutToShow)
        self.history_menu.triggered.connect(self._AH_HistoryMenuTriggered)
        self.output_devices_group.triggered.connect(self._AH_AudioOutputDeviceChanged)
        self.input_devices_group.triggered.connect(self._AH_AudioInputDeviceChanged)
        self.alert_devices_group.triggered.connect(self._AH_AudioAlertDeviceChanged)
        self.video_devices_group.triggered.connect(self._AH_VideoDeviceChanged)
        self.mute_action.triggered.connect(self._SH_MuteButtonClicked)
        self.silent_action.triggered.connect(self._SH_SilentButtonClicked)

        # Tools menu actions
        self.sip_server_settings_action.triggered.connect(self._AH_SIPServerSettings)
        self.search_for_people_action.triggered.connect(self._AH_SearchForPeople)
        self.history_on_server_action.triggered.connect(self._AH_HistoryOnServer)

        # Window menu actions
        self.chat_window_action.triggered.connect(self._AH_ChatWindowActionTriggered)
        self.transfers_window_action.triggered.connect(self._AH_TransfersWindowActionTriggered)
        self.logs_window_action.triggered.connect(self._AH_LogsWindowActionTriggered)
        self.received_files_window_action.triggered.connect(self._AH_ReceivedFilesWindowActionTriggered)
        self.screenshots_window_action.triggered.connect(self._AH_ScreenshotsWindowActionTriggered)
        self.documents_window_action.triggered.connect(self._AH_DocumentsWindowActionTriggered)

    def setupUi(self):
        super(MainWindow, self).setupUi(self)

        self.search_box.shortcut = QShortcut(self.search_box)
        self.search_box.shortcut.setKey('Ctrl+F')

        self.output_devices_group = QActionGroup(self)
        self.input_devices_group = QActionGroup(self)
        self.alert_devices_group = QActionGroup(self)
        self.video_devices_group = QActionGroup(self)

        self.request_screen_action = QAction('Request screen', self, triggered=self._AH_RequestScreenActionTriggered)
        self.share_my_screen_action = QAction('Share my screen', self, triggered=self._AH_ShareMyScreenActionTriggered)
        self.screen_sharing_button.addAction(self.request_screen_action)
        self.screen_sharing_button.addAction(self.share_my_screen_action)

        # adjust search box height depending on theme as the value set in designer isn't suited for all themes
        search_box = self.search_box
        option = QStyleOptionFrameV2()
        search_box.initStyleOption(option)
        frame_width = search_box.style().pixelMetric(QStyle.PM_DefaultFrameWidth, option, search_box)
        if frame_width < 4:
            search_box.setMinimumHeight(20 + 2*frame_width)

        # adjust the combo boxes for themes with too much padding (like the default theme on Ubuntu 10.04)
        option = QStyleOptionComboBox()
        self.identity.initStyleOption(option)
        wide_padding = self.identity.style().subControlRect(QStyle.CC_ComboBox, option, QStyle.SC_ComboBoxEditField, self.identity).height() < 10
        self.identity.setStyleSheet("""QComboBox { padding: 0px 4px 0px 4px; }""" if wide_padding else "")

    def closeEvent(self, event):
        QSettings().setValue("main_window/geometry", self.saveGeometry())
        super(MainWindow, self).closeEvent(event)
        self.about_panel.close()
        self.contact_editor_dialog.close()
        self.google_contacts_dialog.close()
        self.server_tools_window.close()
        for dialog in self.pending_watcher_dialogs[:]:
            dialog.close()

    def show(self):
        super(MainWindow, self).show()
        self.raise_()
        self.activateWindow()

    def set_user_icon(self, icon):
        self.account_state.setIcon(icon or self.default_icon)

    def enable_call_buttons(self, enabled):
        self.audio_call_button.setEnabled(enabled)
        self.video_call_button.setEnabled(enabled)
        self.chat_session_button.setEnabled(enabled)
        self.screen_sharing_button.setEnabled(enabled)
        self.share_document_button.setEnabled(enabled)

    def load_audio_devices(self):
        settings = SIPSimpleSettings()

        action = QAction(u'System default', self.output_devices_group)
        action.setData(u'system_default')
        self.output_device_menu.addAction(action)
        self.output_device_menu.addSeparator()
        for device in SIPApplication.engine.output_devices:
            action = QAction(device, self.output_devices_group)
            action.setData(device)
            self.output_device_menu.addAction(action)
        action = QAction(u'None', self.output_devices_group)
        action.setData(None)
        self.output_device_menu.addAction(action)
        for action in self.output_devices_group.actions():
            action.setCheckable(True)
            if settings.audio.output_device == action.data():
                action.setChecked(True)

        action = QAction(u'System default', self.input_devices_group)
        action.setData(u'system_default')
        self.input_device_menu.addAction(action)
        self.input_device_menu.addSeparator()
        for device in SIPApplication.engine.input_devices:
            action = QAction(device, self.input_devices_group)
            action.setData(device)
            self.input_device_menu.addAction(action)
        action = QAction(u'None', self.input_devices_group)
        action.setData(None)
        self.input_device_menu.addAction(action)
        for action in self.input_devices_group.actions():
            action.setCheckable(True)
            if settings.audio.input_device == action.data():
                action.setChecked(True)

        action = QAction(u'System default', self.alert_devices_group)
        action.setData(u'system_default')
        self.alert_device_menu.addAction(action)
        self.alert_device_menu.addSeparator()
        for device in SIPApplication.engine.output_devices:
            action = QAction(device, self.alert_devices_group)
            action.setData(device)
            self.alert_device_menu.addAction(action)
        action = QAction(u'None', self.alert_devices_group)
        action.setData(None)
        self.alert_device_menu.addAction(action)
        for action in self.alert_devices_group.actions():
            action.setCheckable(True)
            if settings.audio.alert_device == action.data():
                action.setChecked(True)

    def load_video_devices(self):
        settings = SIPSimpleSettings()

        action = QAction(u'System default', self.video_devices_group)
        action.setData(u'system_default')
        self.video_camera_menu.addAction(action)
        self.video_camera_menu.addSeparator()
        for device in SIPApplication.engine.video_devices:
            action = QAction(device, self.video_devices_group)
            action.setData(device)
            self.video_camera_menu.addAction(action)
        action = QAction(u'None', self.video_devices_group)
        action.setData(None)
        self.video_camera_menu.addAction(action)
        for action in self.video_devices_group.actions():
            action.setCheckable(True)
            if settings.video.device == action.data():
                action.setChecked(True)

    def _AH_AccountActionTriggered(self, action, enabled):
        account = action.data()
        account.enabled = enabled
        account.save()

    def _AH_AudioAlertDeviceChanged(self, action):
        settings = SIPSimpleSettings()
        settings.audio.alert_device = action.data()
        settings.save()

    def _AH_AudioInputDeviceChanged(self, action):
        settings = SIPSimpleSettings()
        settings.audio.input_device = action.data()
        settings.save()

    def _AH_AudioOutputDeviceChanged(self, action):
        settings = SIPSimpleSettings()
        settings.audio.output_device = action.data()
        settings.save()

    def _AH_VideoDeviceChanged(self, action):
        settings = SIPSimpleSettings()
        settings.video.device = action.data()
        settings.save()

    def _AH_AutoAcceptChatActionTriggered(self, checked):
        settings = SIPSimpleSettings()
        settings.chat.auto_accept = checked
        settings.save()

    def _AH_ReceivedMessagesSoundActionTriggered(self, checked):
        settings = SIPSimpleSettings()
        settings.sounds.play_message_alerts = checked
        settings.save()

    def _AH_EnableAnsweringMachineActionTriggered(self, checked):
        settings = SIPSimpleSettings()
        settings.answering_machine.enabled = checked
        settings.save()

    def _AH_GoogleContactsActionTriggered(self):
        settings = SIPSimpleSettings()
        if settings.google_contacts.authorization_token is not None:
            settings.google_contacts.authorization_token = None
            settings.save()
            self.google_contacts_dialog.hide()
        else:
            self.google_contacts_dialog.open()

    def _AH_RedialActionTriggered(self):
        session_manager = SessionManager()
        if session_manager.last_dialed_uri is not None:
            contact, contact_uri = URIUtils.find_contact(session_manager.last_dialed_uri)
            session_manager.create_session(contact, contact_uri, [StreamDescription('audio')]) # TODO: remember used media types and redial with them. -Saul

    def _AH_SIPServerSettings(self, checked):
        account = self.identity.itemData(self.identity.currentIndex()).account
        account = account if account is not BonjourAccount() and account.server.settings_url else None
        self.server_tools_window.open_settings_page(account)

    def _AH_SearchForPeople(self, checked):
        account = self.identity.itemData(self.identity.currentIndex()).account
        account = account if account is not BonjourAccount() and account.server.settings_url else None
        self.server_tools_window.open_search_for_people_page(account)

    def _AH_HistoryOnServer(self, checked):
        account = self.identity.itemData(self.identity.currentIndex()).account
        account = account if account is not BonjourAccount() and account.server.settings_url else None
        self.server_tools_window.open_history_page(account)

    def _AH_ChatWindowActionTriggered(self, checked):
        blink = QApplication.instance()
        blink.chat_window.show()

    def _AH_TransfersWindowActionTriggered(self, checked):
        self.filetransfer_window.show()

    def _AH_LogsWindowActionTriggered(self, checked):
        directory = ApplicationData.get('logs')
        makedirs(directory)
        QDesktopServices.openUrl(QUrl.fromLocalFile(directory))

    def _AH_ReceivedFilesWindowActionTriggered(self, checked):
        settings = BlinkSettings()
        directory = settings.transfers_directory.normalized
        makedirs(directory)
        QDesktopServices.openUrl(QUrl.fromLocalFile(directory))

    def _AH_ScreenshotsWindowActionTriggered(self, checked):
        settings = BlinkSettings()
        directory = settings.screenshots_directory.normalized
        makedirs(directory)
        QDesktopServices.openUrl(QUrl.fromLocalFile(directory))

    def _AH_DocumentsWindowActionTriggered(self, checked):
        self.documents_window.show()

    def _AH_VoicemailActionTriggered(self, action, checked):
        account = action.data()
        contact, contact_uri = URIUtils.find_contact(account.voicemail_uri, display_name='Voicemail')
        session_manager = SessionManager()
        session_manager.create_session(contact, contact_uri, [StreamDescription('audio')], account=account)

    def _SH_HistoryMenuAboutToShow(self):
        self.history_menu.clear()
        if self.history_manager.calls:
            for entry in reversed(self.history_manager.calls):
                action = self.history_menu.addAction(entry.icon, entry.text)
                action.entry = entry
                action.setToolTip(entry.uri)
        else:
            action = self.history_menu.addAction("Call history is empty")
            action.setEnabled(False)

    def _AH_HistoryMenuTriggered(self, action):
        account_manager = AccountManager()
        session_manager = SessionManager()
        try:
            account = account_manager.get_account(action.entry.account_id)
        except KeyError:
            account = None
        contact, contact_uri = URIUtils.find_contact(action.entry.uri)
        session_manager.create_session(contact, contact_uri, [StreamDescription('audio')], account=account) # TODO: memorize media type and use it? -Saul (not sure about history in/out -Dan)

    def _AH_SystemTrayShowWindow(self, checked):
        self.show()
        self.raise_()
        self.activateWindow()

    def _AH_QuitActionTriggered(self, checked):
        if self.system_tray_icon is not None:
            self.system_tray_icon.hide()
        QApplication.instance().quit()

    def _SH_AccountStateChanged(self):
        self.activity_note.setText(self.account_state.note)
        if self.account_state.state is AccountState.Invisible:
            self.activity_note.inactiveText = u'(invisible)'
            self.activity_note.setEnabled(False)
        else:
            if not self.activity_note.isEnabled():
                self.activity_note.inactiveText = u'Add an activity note here'
                self.activity_note.setEnabled(True)
        if not self.account_state.state.internal:
            self.saved_account_state = None
        blink_settings = BlinkSettings()
        blink_settings.presence.current_state = PresenceState(self.account_state.state, self.account_state.note)
        blink_settings.presence.state_history = [PresenceState(state, note) for state, note in self.account_state.history]
        blink_settings.save()

    def _SH_AccountStateClicked(self, checked):
        filename = QFileDialog.getOpenFileName(self, u'Select Icon', self.last_icon_directory, u"Images (*.png *.tiff *.jpg *.xmp *.svg)")
        if filename:
            self.last_icon_directory = os.path.dirname(filename)
            filename = filename if os.path.realpath(filename) != os.path.realpath(self.default_icon_path) else None
            blink_settings = BlinkSettings()
            icon_manager = IconManager()
            if filename is not None:
                icon = icon_manager.store_file('avatar', filename)
                if icon is not None:
                    blink_settings.presence.icon = IconDescriptor(FileURL(icon.filename), hashlib.sha1(icon.content).hexdigest())
                else:
                    icon_manager.remove('avatar')
                    blink_settings.presence.icon = None
            else:
                icon_manager.remove('avatar')
                blink_settings.presence.icon = None
            blink_settings.save()

    def _SH_ActivityNoteEditingFinished(self):
        self.activity_note.clearFocus()
        note = self.activity_note.text()
        if note != self.account_state.note:
            self.account_state.state.internal = False
            self.account_state.setState(self.account_state.state, note)

    def _SH_AddContactButtonClicked(self, clicked):
        self.contact_editor_dialog.open_for_add(self.search_box.text(), None)

    def _SH_AudioCallButtonClicked(self):
        list_view = self.contact_list if self.contacts_view.currentWidget() is self.contact_list_panel else self.search_list
        if list_view.detail_view.isVisible():
            list_view.detail_view._AH_StartAudioCall()
        else:
            selected_indexes = list_view.selectionModel().selectedIndexes()
            if selected_indexes:
                contact = selected_indexes[0].data(Qt.UserRole)
                contact_uri = contact.uri
            else:
                contact, contact_uri = URIUtils.find_contact(self.search_box.text())
            session_manager = SessionManager()
            session_manager.create_session(contact, contact_uri, [StreamDescription('audio')])

    def _SH_VideoCallButtonClicked(self):
        list_view = self.contact_list if self.contacts_view.currentWidget() is self.contact_list_panel else self.search_list
        if list_view.detail_view.isVisible():
            list_view.detail_view._AH_StartVideoCall()
        else:
            selected_indexes = list_view.selectionModel().selectedIndexes()
            if selected_indexes:
                contact = selected_indexes[0].data(Qt.UserRole)
                contact_uri = contact.uri
            else:
                contact, contact_uri = URIUtils.find_contact(self.search_box.text())
            session_manager = SessionManager()
            session_manager.create_session(contact, contact_uri, [StreamDescription('audio'), StreamDescription('video')])

    def _SH_ChatSessionButtonClicked(self):
        list_view = self.contact_list if self.contacts_view.currentWidget() is self.contact_list_panel else self.search_list
        if list_view.detail_view.isVisible():
            list_view.detail_view._AH_StartChatSession()
        else:
            selected_indexes = list_view.selectionModel().selectedIndexes()
            if selected_indexes:
                contact = selected_indexes[0].data(Qt.UserRole)
                contact_uri = contact.uri
            else:
                contact, contact_uri = URIUtils.find_contact(self.search_box.text())
            session_manager = SessionManager()
            session_manager.create_session(contact, contact_uri, [StreamDescription('chat')], connect=False)

    def _AH_RequestScreenActionTriggered(self):
        list_view = self.contact_list if self.contacts_view.currentWidget() is self.contact_list_panel else self.search_list
        if list_view.detail_view.isVisible():
            list_view.detail_view._AH_RequestScreen()
        else:
            selected_indexes = list_view.selectionModel().selectedIndexes()
            if selected_indexes:
                contact = selected_indexes[0].data(Qt.UserRole)
                contact_uri = contact.uri
            else:
                contact, contact_uri = URIUtils.find_contact(self.search_box.text())
            session_manager = SessionManager()
            session_manager.create_session(contact, contact_uri, [StreamDescription('screen-sharing', mode='viewer'), StreamDescription('audio')])

    def _AH_ShareMyScreenActionTriggered(self):
        list_view = self.contact_list if self.contacts_view.currentWidget() is self.contact_list_panel else self.search_list
        if list_view.detail_view.isVisible():
            list_view.detail_view._AH_ShareMyScreen()
        else:
            selected_indexes = list_view.selectionModel().selectedIndexes()
            if selected_indexes:
                contact = selected_indexes[0].data(Qt.UserRole)
                contact_uri = contact.uri
            else:
                contact, contact_uri = URIUtils.find_contact(self.search_box.text())
            session_manager = SessionManager()
            session_manager.create_session(contact, contact_uri, [StreamDescription('screen-sharing', mode='server'), StreamDescription('audio')])

    def _SH_ShareDocumentButtonClicked(self):
        list_view = self.contact_list if self.contacts_view.currentWidget() is self.contact_list_panel else self.search_list

        selected_indexes = list_view.selectionModel().selectedIndexes()
        if selected_indexes:
            contact = selected_indexes[0].data(Qt.UserRole)
            contact_uri = contact.uri
        else:
            contact, contact_uri = URIUtils.find_contact(self.search_box.text())

        filename = QFileDialog.getOpenFileName(self, "Share a Document", "", "OpenDocument Files (*.odt)")

        if filename:
            session_manager = SessionManager()
            session_manager.create_session(contact, contact_uri, [StreamDescription('document-sharing', filename=filename)])


    def _SH_BreakConference(self):
        active_session = self.session_list.selectionModel().selectedIndexes()[0].data(Qt.UserRole)
        self.session_model.breakConference(active_session.client_conference)

    def _SH_ContactListSelectionChanged(self, selected, deselected):
        account_manager = AccountManager()
        selected_items = self.contact_list.selectionModel().selectedIndexes()
        self.enable_call_buttons(account_manager.default_account is not None and len(selected_items)==1 and isinstance(selected_items[0].data(Qt.UserRole), Contact))

    def _SH_ContactModelAddedItems(self, items):
        if not self.search_box.text():
            return
        active_widget = self.search_list_panel if self.contact_search_model.rowCount() else self.not_found_panel
        self.search_view.setCurrentWidget(active_widget)

    def _SH_ContactModelRemovedItems(self, items):
        if not self.search_box.text():
            return
        if any(type(item) is Contact for item in items) and self.contact_search_model.rowCount() == 0:
            self.search_box.clear() # check this. it is no longer be the correct behaviour as now contacts can be deleted from remote -Dan
        else:
            active_widget = self.search_list_panel if self.contact_search_model.rowCount() else self.not_found_panel
            self.search_view.setCurrentWidget(active_widget)

    def _SH_DisplayNameEditingFinished(self):
        self.display_name.clearFocus()
        index = self.identity.currentIndex()
        if index != -1:
            name = self.display_name.text()
            account = self.identity.itemData(index).account
            account.display_name = name if name else None
            account.save()

    def _SH_HangupAllButtonClicked(self):
        for session in self.session_model.sessions:
            session.end()

    def _SH_IdentityChanged(self, index):
        account_manager = AccountManager()
        account_manager.default_account = self.identity.itemData(index).account

    def _SH_IdentityCurrentIndexChanged(self, index):
        if index != -1:
            account = self.identity.itemData(index).account
            self.display_name.setText(account.display_name or u'')
            self.display_name.setEnabled(True)
            self.activity_note.setEnabled(True)
            self.account_state.setEnabled(True)
        else:
            self.display_name.clear()
            self.display_name.setEnabled(False)
            self.activity_note.setEnabled(False)
            self.account_state.setEnabled(False)
            self.account_state.setState(AccountState.Invisible)
            self.saved_account_state = None

    def _SH_MakeConference(self):
        self.session_model.conferenceSessions([session for session in self.session_model.active_sessions if session.client_conference is None])

    def _SH_MuteButtonClicked(self, muted):
        settings = SIPSimpleSettings()
        settings.audio.muted = muted
        settings.save()

    def _SH_SearchBoxReturnPressed(self):
        address = self.search_box.text()
        if address:
            contact, contact_uri = URIUtils.find_contact(address)
            session_manager = SessionManager()
            session_manager.create_session(contact, contact_uri, [StreamDescription('audio')])

    def _SH_SearchBoxTextChanged(self, text):
        self.contact_search_model.setFilterFixedString(text)
        account_manager = AccountManager()
        if text:
            self.switch_view_button.view = SwitchViewButton.ContactView
            if self.contacts_view.currentWidget() is not self.search_panel:
                self.search_list.selectionModel().clearSelection()
            self.contacts_view.setCurrentWidget(self.search_panel)
            self.search_view.setCurrentWidget(self.search_list_panel if self.contact_search_model.rowCount() else self.not_found_panel)
            selected_items = self.search_list.selectionModel().selectedIndexes()
            self.enable_call_buttons(account_manager.default_account is not None and len(selected_items)<=1)
        else:
            self.contacts_view.setCurrentWidget(self.contact_list_panel)
            selected_items = self.contact_list.selectionModel().selectedIndexes()
            self.enable_call_buttons(account_manager.default_account is not None and len(selected_items)==1 and type(selected_items[0].data(Qt.UserRole)) is Contact)
        self.search_list.detail_model.contact = None
        self.search_list.detail_view.hide()

    def _SH_SearchListSelectionChanged(self, selected, deselected):
        account_manager = AccountManager()
        selected_items = self.search_list.selectionModel().selectedIndexes()
        self.enable_call_buttons(account_manager.default_account is not None and len(selected_items)<=1)

    def _SH_ServerToolsAccountModelChanged(self, parent_index, start, end):
        server_tools_enabled = self.server_tools_account_model.rowCount() > 0
        self.sip_server_settings_action.setEnabled(server_tools_enabled)
        self.search_for_people_action.setEnabled(server_tools_enabled)
        self.history_on_server_action.setEnabled(server_tools_enabled)

    def _SH_SessionListSelectionChanged(self, selected, deselected):
        selected_indexes = selected.indexes()
        active_session = selected_indexes[0].data(Qt.UserRole) if selected_indexes else Null
        if active_session.client_conference:
            self.conference_button.setEnabled(True)
            self.conference_button.setChecked(True)
        else:
            self.conference_button.setEnabled(len([session for session in self.session_model.active_sessions if session.client_conference is None]) > 1)
            self.conference_button.setChecked(False)

    def _SH_AudioSessionModelAddedSession(self, session_item):
        if len(session_item.blink_session.streams) == 1:
            self.switch_view_button.view = SwitchViewButton.SessionView

    def _SH_AudioSessionModelRemovedSession(self, session_item):
        if self.session_model.rowCount() == 0:
            self.switch_view_button.view = SwitchViewButton.ContactView

    def _SH_AudioSessionModelChangedStructure(self):
        active_sessions = self.session_model.active_sessions
        self.active_sessions_label.setText(u'There is 1 active call' if len(active_sessions)==1 else u'There are %d active calls' % len(active_sessions))
        self.active_sessions_label.setVisible(any(active_sessions))
        self.hangup_all_button.setEnabled(any(active_sessions))
        selected_indexes = self.session_list.selectionModel().selectedIndexes()
        active_session = selected_indexes[0].data(Qt.UserRole) if selected_indexes else Null
        if active_session.client_conference:
            self.conference_button.setEnabled(True)
            self.conference_button.setChecked(True)
        else:
            self.conference_button.setEnabled(len([session for session in active_sessions if session.client_conference is None]) > 1)
            self.conference_button.setChecked(False)
        if active_sessions:
            if self.account_state.state is not AccountState.Invisible:
                if self.saved_account_state is None:
                    self.saved_account_state = self.account_state.state, self.activity_note.text()
                self.account_state.setState(AccountState.Busy.Internal, note=u'On the phone')
        elif self.saved_account_state is not None:
            state, note = self.saved_account_state
            self.saved_account_state = None
            self.account_state.setState(state, note)

    def _SH_SilentButtonClicked(self, silent):
        settings = SIPSimpleSettings()
        settings.audio.silent = silent
        settings.save()

    def _SH_SwitchViewButtonChangedView(self, view):
        self.main_view.setCurrentWidget(self.contacts_panel if view is SwitchViewButton.ContactView else self.sessions_panel)

    def _SH_PendingWatcherDialogFinished(self, result):
        self.pending_watcher_dialogs.remove(self.sender())

    def _SH_SystemTrayIconActivated(self, reason):
        if reason == QSystemTrayIcon.Trigger:
            self.show()
            self.raise_()
            self.activateWindow()

    @run_in_gui_thread
    def handle_notification(self, notification):
        handler = getattr(self, '_NH_%s' % notification.name, Null)
        handler(notification)

    def _NH_SIPApplicationWillStart(self, notification):
        account_manager = AccountManager()
        settings = SIPSimpleSettings()
        self.silent_action.setChecked(settings.audio.silent)
        self.silent_button.setChecked(settings.audio.silent)
        self.answering_machine_action.setChecked(settings.answering_machine.enabled)
        self.auto_accept_chat_action.setChecked(settings.chat.auto_accept)
        self.received_messages_sound_action.setChecked(settings.sounds.play_message_alerts)
        if settings.google_contacts.authorization_token is None:
            self.google_contacts_action.setText(u'Enable &Google Contacts...')
        else:
            self.google_contacts_action.setText(u'Disable &Google Contacts')
        self.google_contacts_action.triggered.connect(self._AH_GoogleContactsActionTriggered)
        if not any(account.enabled for account in account_manager.iter_accounts()):
            self.display_name.setEnabled(False)
            self.activity_note.setEnabled(False)
            self.account_state.setEnabled(False)

    def _NH_SIPApplicationDidStart(self, notification):
        self.load_audio_devices()
        self.load_video_devices()
        notification.center.add_observer(self, name='CFGSettingsObjectDidChange')
        notification.center.add_observer(self, name='AudioDevicesDidChange')
        blink_settings = BlinkSettings()
        self.account_state.history = [(item.state, item.note) for item in blink_settings.presence.state_history]
        state = getattr(AccountState, blink_settings.presence.current_state.state, AccountState.Available)
        self.account_state.setState(state, blink_settings.presence.current_state.note)

    def _NH_AudioDevicesDidChange(self, notification):
        for action in self.output_device_menu.actions():
            self.output_devices_group.removeAction(action)
            self.output_device_menu.removeAction(action)
        for action in self.input_device_menu.actions():
            self.input_devices_group.removeAction(action)
            self.input_device_menu.removeAction(action)
        for action in self.alert_device_menu.actions():
            self.alert_devices_group.removeAction(action)
            self.alert_device_menu.removeAction(action)
        if self.session_model.active_sessions:
            old_devices = set(notification.data.old_devices)
            new_devices = set(notification.data.new_devices)
            added_devices = new_devices - old_devices
            if added_devices:
                new_device = added_devices.pop()
                settings = SIPSimpleSettings()
                settings.audio.input_device = new_device
                settings.audio.output_device = new_device
                settings.save()
        self.load_audio_devices()

    def _NH_CFGSettingsObjectDidChange(self, notification):
        settings = SIPSimpleSettings()
        blink_settings = BlinkSettings()
        icon_manager = IconManager()
        if notification.sender is settings:
            if 'audio.muted' in notification.data.modified:
                self.mute_action.setChecked(settings.audio.muted)
                self.mute_button.setChecked(settings.audio.muted)
            if 'audio.silent' in notification.data.modified:
                self.silent_action.setChecked(settings.audio.silent)
                self.silent_button.setChecked(settings.audio.silent)
            if 'audio.output_device' in notification.data.modified:
                action = (action for action in self.output_devices_group.actions() if action.data() == settings.audio.output_device).next()
                action.setChecked(True)
            if 'audio.input_device' in notification.data.modified:
                action = (action for action in self.input_devices_group.actions() if action.data() == settings.audio.input_device).next()
                action.setChecked(True)
            if 'audio.alert_device' in notification.data.modified:
                action = (action for action in self.alert_devices_group.actions() if action.data() == settings.audio.alert_device).next()
                action.setChecked(True)
            if 'video.device' in notification.data.modified:
                action = (action for action in self.video_devices_group.actions() if action.data() == settings.video.device).next()
                action.setChecked(True)
            if 'answering_machine.enabled' in notification.data.modified:
                self.answering_machine_action.setChecked(settings.answering_machine.enabled)
            if 'chat.auto_accept' in notification.data.modified:
                self.auto_accept_chat_action.setChecked(settings.chat.auto_accept)
            if 'sounds.play_message_alerts' in notification.data.modified:
                self.received_messages_sound_action.setChecked(settings.sounds.play_message_alerts)
            if 'google_contacts.authorization_token' in notification.data.modified:
                authorization_token = notification.sender.google_contacts.authorization_token
                if authorization_token is None:
                    self.google_contacts_action.setText(u'Enable &Google Contacts...')
                else:
                    self.google_contacts_action.setText(u'Disable &Google Contacts')
                if authorization_token is InvalidToken:
                    self.google_contacts_dialog.open_for_incorrect_password()
        elif notification.sender is blink_settings:
            if 'presence.current_state' in notification.data.modified:
                state = getattr(AccountState, blink_settings.presence.current_state.state, AccountState.Available)
                self.account_state.setState(state, blink_settings.presence.current_state.note)
            if 'presence.icon' in notification.data.modified:
                self.set_user_icon(icon_manager.get('avatar'))
            if 'presence.offline_note' in notification.data.modified:
                # TODO: set offline note -Saul
                pass
        elif isinstance(notification.sender, (Account, BonjourAccount)):
            account_manager = AccountManager()
            account = notification.sender
            if 'enabled' in notification.data.modified:
                action = (action for action in self.accounts_menu.actions() if action.data() is account).next()
                action.setChecked(account.enabled)
            if 'display_name' in notification.data.modified and account is account_manager.default_account:
                self.display_name.setText(account.display_name or u'')
            if set(['enabled', 'message_summary.enabled', 'message_summary.voicemail_uri']).intersection(notification.data.modified):
                action = (action for action in self.voicemail_menu.actions() if action.data() is account).next()
                action.setVisible(False if account is BonjourAccount() else account.enabled and account.message_summary.enabled)
                action.setEnabled(False if account is BonjourAccount() else account.voicemail_uri is not None)

    def _NH_SIPAccountManagerDidAddAccount(self, notification):
        account = notification.data.account
        action = QAction(account.id if account is not BonjourAccount() else u'Bonjour', None)
        action.setEnabled(True if account is not BonjourAccount() else BonjourAccount.mdns_available)
        action.setCheckable(True)
        action.setChecked(account.enabled)
        action.setData(account)
        action.triggered.connect(partial(self._AH_AccountActionTriggered, action))
        self.accounts_menu.addAction(action)
        action = QAction(self.mwi_icons[0], account.id, None)
        action.setVisible(False if account is BonjourAccount() else account.enabled and account.message_summary.enabled)
        action.setEnabled(False if account is BonjourAccount() else account.voicemail_uri is not None)
        action.setData(account)
        action.triggered.connect(partial(self._AH_VoicemailActionTriggered, action))
        self.voicemail_menu.addAction(action)

    def _NH_SIPAccountManagerDidRemoveAccount(self, notification):
        account = notification.data.account
        action = (action for action in self.accounts_menu.actions() if action.data() is account).next()
        self.accounts_menu.removeAction(action)
        action = (action for action in self.voicemail_menu.actions() if action.data() is account).next()
        self.voicemail_menu.removeAction(action)

    def _NH_SIPAccountManagerDidChangeDefaultAccount(self, notification):
        if notification.data.account is None:
            self.enable_call_buttons(False)
        else:
            selected_items = self.contact_list.selectionModel().selectedIndexes()
            self.enable_call_buttons(len(selected_items)==1 and isinstance(selected_items[0].data(Qt.UserRole), Contact))

    def _NH_SIPAccountGotMessageSummary(self, notification):
        account = notification.sender
        summary = notification.data.message_summary
        action = (action for action in self.voicemail_menu.actions() if action.data() is account).next()
        action.setEnabled(account.voicemail_uri is not None)
        if summary.messages_waiting:
            try:
                new_messages = limit(int(summary.summaries['voice-message']['new_messages']), min=0, max=11)
            except (KeyError, ValueError):
                new_messages = 0
        else:
            new_messages = 0
        action.setIcon(self.mwi_icons[new_messages])

    def _NH_SIPAccountGotPendingWatcher(self, notification):
        dialog = PendingWatcherDialog(notification.sender, notification.data.uri, notification.data.display_name)
        dialog.finished.connect(self._SH_PendingWatcherDialogFinished)
        self.pending_watcher_dialogs.append(dialog)
        dialog.show()

    def _NH_BlinkSessionNewOutgoing(self, notification):
        self.search_box.clear()

    def _NH_BlinkSessionDidReinitializeForOutgoing(self, notification):
        self.search_box.clear()

    def _NH_BlinkFileTransferNewIncoming(self, notification):
        self.filetransfer_window.show(activate=QApplication.activeWindow() is not None)

    def _NH_BlinkFileTransferNewOutgoing(self, notification):
        self.filetransfer_window.show(activate=QApplication.activeWindow() is not None)
示例#41
0
文件: gui.py 项目: jianlins/lpfw
        pass
    elif (sys.argv[1] != "debug"):
        import wingdbstub

    app=QApplication(sys.argv)
    app.setQuitOnLastWindowClosed(False)
    window = myMainWindow()

    tray = QSystemTrayIcon(QIcon(":/pics/pic24.png"))
    menu = QMenu()
    actionShow = QAction("Show Leopard Flower",menu)
    actionExit = QAction("Exit",menu)
    menu.addAction(actionShow)
    menu.addAction(actionExit)
    tray.setContextMenu(menu)
    tray.show()
    actionShow.triggered.connect(window.show)
    actionExit.triggered.connect(window.realQuit)

    sourcemodel = myModel()  
    model = mySortFilterProxyModel()
    model.setSourceModel(sourcemodel)
    model.setDynamicSortFilter(True)

    window.tableView.setSortingEnabled(True)
    window.tableView.setModel(model)
    window.model = model
    window.sourcemodel = sourcemodel

    delegate = CustomDelegate()    
    window.tableView.setItemDelegateForColumn(4,delegate)
示例#42
0
class MainWindow(QWidget):
    def __init__(self):
        super(QWidget, self).__init__()
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

        self.systemTray = QSystemTrayIcon(self)
        self.systemTray.setIcon(QIcon(':/images/icon.png'))
        self.act_autostart = QAction('开机启动', self)
        self.act_autostart.setCheckable(True)
        is_autostart = self.is_autostart()
        self.act_autostart.setChecked(is_autostart)
        self.act_autostart.triggered.connect(self.on_autostart)
        act_setting = QAction('设置启动项', self)
        act_setting.triggered.connect(self.on_settings)
        act_exit = QAction('退出', self)
        act_exit.triggered.connect(self.on_exit)
        self.menu_run = QMenu('运行', self)
        menu = QMenu('菜单', self)
        menu.addMenu(self.menu_run)
        menu.addAction(act_setting)
        menu.addSeparator()
        menu.addAction(self.act_autostart)
        menu.addAction(act_exit)
        self.systemTray.setContextMenu(menu)
        self.systemTray.show()
        self.showMessage('启动工具正在运行')

        self.ui.btn_add.clicked.connect(self.on_add)
        self.ui.btn_delete.clicked.connect(self.on_delete)
        self.ui.btn_apply.clicked.connect(self.on_apply)
        self.ui.btn_env_add.clicked.connect(self.on_env_add)
        self.ui.btn_env_del.clicked.connect(self.on_env_del)
        self.ui.btn_open.clicked.connect(self.on_open)
        self.ui.btn_run.clicked.connect(self.on_run)
        self.ui.le_args.textEdited.connect(self.on_edited)
        self.ui.le_desc.textEdited.connect(self.on_edited)
        self.ui.le_exe.textEdited.connect(self.on_edited)
        self.ui.cb_process.currentIndexChanged.connect(self.on_index_changed)
        self.ui.le_exe.installEventFilter(self)
        self.init()

    def eventFilter(self, obj, event):
        if event.type() == QEvent.DragEnter:
            # we need to accept this event explicitly to be able to receive QDropEvents!
            event.accept()
        if event.type() == QEvent.Drop:
            md = event.mimeData()
            urls = md.urls()
            if (urls and urls[0].scheme() == 'file'):
                # for some reason, this doubles up the intro slash
                filepath = urls[0].path().mid(1)
                self.ui.le_exe.setText(filepath)
                self.modify = True
                self.ui.btn_apply.setEnabled(True)
            event.accept()
        return QObject.eventFilter(self, obj, event)

    def showMessage(self, msg):
        self.systemTray.showMessage('Launcher', msg,
                                    QSystemTrayIcon.Information, 10000)

    def config_dir(self):
        confd = QString2str(
            QApplication.applicationDirPath()) + os.sep + 'configs'
        dir = QDir(confd)
        if not dir.exists():
            dir.mkpath(confd)
        return confd

    def on_settings(self):
        self.show()

    def on_exit(self):
        QtGui.qApp.quit()

    def on_edited(self):
        self.modify = True
        self.ui.btn_apply.setEnabled(True)

    def on_apply(self):
        if self.currentProcess is None:
            QMessageBox.warning(self, '警告', '未选择有效启动项,无法完成保存!')
            return
        args = self.ui.le_args.text()
        exe = self.ui.le_exe.text()
        desc = self.ui.le_desc.text()
        isInherit = self.ui.cb_inheri.checkState() == QtCore.Qt.Checked
        self.currentProcess.setArgs(QString2str(args))
        self.currentProcess.setExe(QString2str(exe))
        self.currentProcess.setDesc(QString2str(desc))
        self.currentProcess.setIsInherit(isInherit)
        envs = {}
        for i in range(self.ui.tw_envs.rowCount()):
            key = self.ui.tw_envs.item(i, 0).text()
            value = self.ui.tw_envs.item(i, 1).text()
            envs[QString2str(key)] = QString2str(value)
        self.currentProcess.setEnvs(envs)
        self.processDict[self.currentProcess.getName()] = self.currentProcess
        configDir = self.config_dir()
        configFilePath = configDir + os.sep + self.currentProcess.getName(
        ) + '.json'
        with open(configFilePath, 'w+') as f:
            f.write(self.currentProcess.save())
        self.modify = False
        self.ui.btn_apply.setEnabled(False)
        QMessageBox.information(self, '提示', '已保存!')

    def on_add(self):
        ret = QInputDialog.getText(self, '请输入启动项目名称', '名称')
        if not ret[1]:
            return
        name = ret[0]
        if name.isEmpty():
            return
        if self.processDict.has_key(QString2str(name)):
            QMessageBox.warning(self, '警告', '该启动项已存在!')
            return
        curProcess = Process()
        curProcess.setName(QString2str(name))
        configDir = self.config_dir()
        configFilePath = configDir + os.sep + QString2str(name) + '.json'
        with open(configFilePath, 'w+') as f:
            f.write(curProcess.save())
        self.add_item(curProcess)
        self.ui.cb_process.setCurrentIndex(self.ui.cb_process.count() - 1)

    def on_delete(self):
        name = self.ui.cb_process.currentText()
        index = self.ui.cb_process.currentIndex()
        if not self.processDict.has_key(QString2str(name)):
            QMessageBox.warning(self, '警告', '请先选择要删除的配置项!')
            return
        process = self.processDict.pop(QString2str(name))
        for action in self.menu_run.actions():
            if action.text() == name:
                self.menu_run.removeAction(action)
        self.ui.cb_process.removeItem(index)
        configFilePath = self.config_dir() + os.sep + QString2str(
            name) + '.json'
        os.remove(configFilePath)

    def on_index_changed(self, index):
        if self.modify and QMessageBox.question(
                self, '提示', '启动项已修改,是否保存?',
                QMessageBox.Yes | QMessageBox.No) == QMessageBox.Yes:
            self.on_apply()
        name = self.ui.cb_process.itemText(index)
        self.reset()
        if self.processDict.has_key(QString2str(name)):
            process = self.processDict[QString2str(name)]
            self.currentProcess = process
            self.display(process)

    def on_env_add(self):
        self.ui.tw_envs.setRowCount(self.ui.tw_envs.rowCount() + 1)
        self.modify = True
        self.ui.btn_apply.setEnabled(True)

    def on_env_del(self):
        index = self.ui.tw_envs.currentRow()
        self.ui.tw_envs.removeRow(index)
        self.modify = True
        self.ui.btn_apply.setEnabled(True)

    def on_run(self):
        if self.modify and QMessageBox.question(
                self, '提示', '启动项已修改,是否保存?',
                QMessageBox.Yes | QMessageBox.No) == QMessageBox.Yes:
            self.on_apply()
        name = self.ui.cb_process.currentText()
        if self.processDict.has_key(QString2str(name)):
            process = self.processDict[QString2str(name)]
            if process.start():
                self.showMessage(u'%s启动项已执行' % process.getName())
            else:
                self.showMessage(u'%s启动项执行失败,请检查配置' % process.getName())
        else:
            QMessageBox.warning(self, '警告', '请先选择要运行的启动项!')

    def on_action_run(self):
        name = self.sender().text()
        if self.processDict.has_key(QString2str(name)):
            process = self.processDict[QString2str(name)]
            if process.start():
                self.showMessage(u'%s启动项已执行' % process.getName())
            else:
                self.showMessage(u'%s启动项执行失败,请检查配置' % process.getName())
        else:
            QMessageBox.warning(self, '警告', '请先选择要运行的启动项!')

    def on_open(self):
        filePath = QFileDialog.getOpenFileName(self, '选择程序')
        self.ui.le_exe.setText(filePath)
        self.modify = True
        self.ui.btn_apply.setEnabled(True)

    def closeEvent(self, event):
        event.ignore()
        self.hide()

    def add_item(self, process):
        self.processDict[process.getName()] = process
        self.ui.cb_process.addItem(process.getName())
        act = self.menu_run.addAction(process.getName())
        act.triggered.connect(self.on_action_run)

    def init(self):
        self.modify = False
        self.ui.btn_apply.setEnabled(False)
        self.currentProcess = None
        self.processDict = {}
        config_dir = self.config_dir()
        items = os.listdir(config_dir)
        for item in items:
            currentPath = self.config_dir() + os.sep + item
            if not os.path.isdir(currentPath) and os.path.exists(currentPath):
                with open(currentPath, 'r') as f:
                    content = f.read()
                    process = Process()
                    if process.load(content):
                        self.add_item(process)

    def reset(self):
        self.ui.le_args.setText('')
        self.ui.le_exe.setText('')
        self.ui.le_desc.setText('')
        self.ui.tw_envs.clear()
        self.ui.tw_envs.setRowCount(0)
        self.modify = False
        self.ui.btn_apply.setEnabled(False)

    def display(self, process):
        self.ui.le_args.setText(process.getArgs())
        self.ui.le_exe.setText(process.getExe())
        self.ui.le_desc.setText(process.getDesc())
        envs = process.getEnvs()
        for key in envs.keys():
            row = self.ui.tw_envs.rowCount()
            self.ui.tw_envs.setRowCount(row + 1)
            self.ui.tw_envs.setItem(row, 0, QTableWidgetItem(key))
            self.ui.tw_envs.setItem(row, 1, QTableWidgetItem(envs[key]))

    def on_autostart(self):
        if self.act_autostart.isChecked():
            self.set_autostart(True)
            self.showMessage('已设置开机启动')
        else:
            self.set_autostart(False)
            self.showMessage('已取消开机启动')

    def is_autostart(self):
        reg = QSettings(
            "HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run",
            QSettings.NativeFormat)
        return reg.contains("launcher")

    def set_autostart(self, auto):
        path = QApplication.applicationFilePath()
        path = QDir.toNativeSeparators(path)
        reg = QSettings(
            "HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run",
            QSettings.NativeFormat)
        if auto is True:
            reg.setValue("launcher", QVariant(QString('"%1"').arg(path)))
        else:
            reg.remove("launcher")