Ejemplo n.º 1
0
class Slider(QWidget):
    def __init__(self,
                 caption,
                 default_value,
                 minimum_value=1,
                 maximum_value=60,
                 single_step=1,
                 page_step=6,
                 caption_size=None,
                 unit='',
                 time=False,
                 tooltip=''):
        QWidget.__init__(self)

        self.value = default_value
        self.unit = unit
        self.time = time

        description = QLabel(caption)
        description.setWordWrap(True)
        description.setToolTip(tooltip)
        if caption_size:
            description.setMaximumWidth(caption_size)

        self.slider = QSlider(Qt.Horizontal)
        self.slider.setMaximum(maximum_value)
        self.slider.setMinimum(minimum_value)
        self.slider.setSingleStep(single_step)
        self.slider.setPageStep(page_step)
        self.slider.setToolTip(tooltip)
        #self.slider.setTickInterval(2)
        #self.slider.setTickPosition(QSlider.TicksBelow)
        self.slider.valueChanged.connect(self.__on_change)

        self.value_label = QLabel()

        hbox = QHBoxLayout()
        hbox.addWidget(description)
        hbox.addWidget(self.slider)
        hbox.addWidget(self.value_label)
        hbox.setMargin(0)
        self.setLayout(hbox)
        self.setContentsMargins(5, 0, 5, 0)
        self.slider.setValue(self.value)
        self.__on_change(self.value)

    def __on_change(self, value):
        # FIXME: Fill with spaces to reach the maximum length
        self.value = value
        unit = self.unit
        if self.time:
            minutes = timedelta(minutes=self.value)
            date = datetime(1, 1, 1) + minutes
            text = "%02dh %02dm" % (date.hour, date.minute)
        else:
            text = "%s %s" % (self.value, self.unit)
        self.value_label.setText(text)

    def get_value(self):
        return int(self.slider.value())
Ejemplo n.º 2
0
class Widget(QWidget):
    def __init__(self, dockwidget):
        super(Widget, self).__init__(dockwidget)
        self._document = None
        self._fileSelector = QComboBox(editable=True,
                                       insertPolicy=QComboBox.NoInsert)
        widgets.drag.ComboDrag(self._fileSelector).role = Qt.UserRole
        self._fileSelector.lineEdit().setReadOnly(True)
        self._fileSelector.lineEdit().setFocusPolicy(Qt.NoFocus)
        self._stopButton = QToolButton()
        self._playButton = QToolButton()
        self._timeSlider = QSlider(Qt.Horizontal,
                                   tracking=False,
                                   singleStep=500,
                                   pageStep=5000,
                                   invertedControls=True)
        self._display = Display()
        self._tempoFactor = QSlider(Qt.Vertical,
                                    minimum=-50,
                                    maximum=50,
                                    singleStep=1,
                                    pageStep=5)

        grid = QGridLayout(spacing=0)
        self.setLayout(grid)

        grid.addWidget(self._fileSelector, 0, 0, 1, 3)
        grid.addWidget(self._stopButton, 1, 0)
        grid.addWidget(self._playButton, 1, 1)
        grid.addWidget(self._timeSlider, 1, 2)
        grid.addWidget(self._display, 2, 0, 1, 3)
        grid.addWidget(self._tempoFactor, 0, 3, 3, 1)

        # size policy of combo
        p = self._fileSelector.sizePolicy()
        p.setHorizontalPolicy(QSizePolicy.Ignored)
        self._fileSelector.setSizePolicy(p)

        # size policy of combo popup
        p = self._fileSelector.view().sizePolicy()
        p.setHorizontalPolicy(QSizePolicy.MinimumExpanding)
        self._fileSelector.view().setSizePolicy(p)

        self._player = player.Player()
        self._outputCloseTimer = QTimer(interval=60000,
                                        singleShot=True,
                                        timeout=self.closeOutput)
        self._timeSliderTicker = QTimer(interval=200,
                                        timeout=self.updateTimeSlider)
        self._fileSelector.activated[int].connect(self.slotFileSelected)
        self._tempoFactor.valueChanged.connect(self.slotTempoChanged)
        self._timeSlider.valueChanged.connect(self.slotTimeSliderChanged)
        self._timeSlider.sliderMoved.connect(self.slotTimeSliderMoved)
        self._player.beat.connect(self.updateDisplayBeat)
        self._player.time.connect(self.updateDisplayTime)
        self._player.stateChanged.connect(self.slotPlayerStateChanged)
        self.slotPlayerStateChanged(False)
        dockwidget.mainwindow().currentDocumentChanged.connect(
            self.loadResults)
        app.documentLoaded.connect(self.slotUpdatedFiles)
        app.jobFinished.connect(self.slotUpdatedFiles)
        app.aboutToQuit.connect(self.stop)
        midihub.aboutToRestart.connect(self.slotAboutToRestart)
        midihub.settingsChanged.connect(self.clearMidiSettings, -100)
        midihub.settingsChanged.connect(self.readMidiSettings)
        app.documentClosed.connect(self.slotDocumentClosed)
        app.translateUI(self)
        self.readMidiSettings()
        d = dockwidget.mainwindow().currentDocument()
        if d:
            self.loadResults(d)

    def translateUI(self):
        self._tempoFactor.setToolTip(_("Tempo"))

    def slotAboutToRestart(self):
        self.stop()
        self._player.set_output(None)

    def clearMidiSettings(self):
        """Called first when settings are changed."""
        self.stop()
        self._outputCloseTimer.stop()
        self._player.set_output(None)

    def readMidiSettings(self):
        """Called after clearMidiSettings(), and on first init."""
        pass

    def openOutput(self):
        """Called when playing starts. Ensures an output port is opened."""
        self._outputCloseTimer.stop()
        if not self._player.output():
            p = QSettings().value("midi/player/output_port",
                                  midihub.default_output(), type(""))
            o = midihub.output_by_name(p)
            if o:
                self._player.set_output(output.Output(o))

    def closeOutput(self):
        """Called when the output close timer fires. Closes the output."""
        self._player.set_output(None)

    def slotPlayerStateChanged(self, playing):
        ac = self.parentWidget().actionCollection
        # setDefaultAction also adds the action
        for b in self._stopButton, self._playButton:
            while b.actions():
                b.removeAction(b.actions()[0])
        if playing:
            self._timeSliderTicker.start()
            self._stopButton.setDefaultAction(ac.midi_stop)
            self._playButton.setDefaultAction(ac.midi_pause)
        else:
            self._timeSliderTicker.stop()
            self.updateTimeSlider()
            self._stopButton.setDefaultAction(ac.midi_restart)
            self._playButton.setDefaultAction(ac.midi_play)
            # close the output if the preference is set
            if QSettings().value("midi/close_outputs", False, bool):
                self._outputCloseTimer.start()

    def play(self):
        """Starts the MIDI player, opening an output if necessary."""
        if not self._player.is_playing() and not self._player.has_events():
            self.restart()
        self.openOutput()
        if not self._player.output():
            self._display.statusMessage(_("No output found!"))
        self._player.start()

    def stop(self):
        """Stops the MIDI player."""
        self._player.stop()

    def restart(self):
        """Restarts the MIDI player.
        
        If another file is in the file selector, or the file was updated,
        the new file is loaded.
        
        """
        self._player.seek(0)
        self.updateTimeSlider()
        self._display.reset()
        if self._document:
            files = midifiles.MidiFiles.instance(self._document)
            index = self._fileSelector.currentIndex()
            if files and (files.song(index) is not self._player.song()):
                self.loadSong(index)

    def slotTempoChanged(self, value):
        """Called when the user drags the tempo."""
        # convert -50 to 50 to 0.5 to 2.0
        factor = 2**(value / 50.0)
        self._player.set_tempo_factor(factor)
        self._display.setTempo("{0}%".format(int(factor * 100)))

    def slotTimeSliderChanged(self, value):
        self._player.seek(value)
        self._display.setTime(value)
        if self._player.song():
            self._display.setBeat(*self._player.song().beat(value)[1:])

    def slotTimeSliderMoved(self, value):
        self._display.setTime(value)
        if self._player.song():
            self._display.setBeat(*self._player.song().beat(value)[1:])

    def updateTimeSlider(self):
        if not self._timeSlider.isSliderDown():
            with qutil.signalsBlocked(self._timeSlider):
                self._timeSlider.setMaximum(self._player.total_time())
                self._timeSlider.setValue(self._player.current_time())

    def updateDisplayBeat(self, measnum, beat, num, den):
        if not self._timeSlider.isSliderDown():
            self._display.setBeat(measnum, beat, num, den)

    def updateDisplayTime(self, time):
        if not self._timeSlider.isSliderDown():
            self._display.setTime(time)

    def slotUpdatedFiles(self, document):
        """Called when there are new MIDI files."""
        if document == self.parentWidget().mainwindow().currentDocument():
            self.loadResults(document)

    def loadResults(self, document):
        self._document = document
        files = midifiles.MidiFiles.instance(document)
        self._fileSelector.setModel(files.model())
        if files:
            self._fileSelector.setCurrentIndex(files.current)
            if not self._player.is_playing():
                self.loadSong(files.current)

    def loadSong(self, index):
        files = midifiles.MidiFiles.instance(self._document)
        self._player.set_song(files.song(index))
        m, s = divmod(self._player.total_time() // 1000, 60)
        name = self._fileSelector.currentText()
        self.updateTimeSlider()
        self._display.reset()
        self._display.statusMessage(_("midi lcd screen", "LOADED"), name,
                                    _("midi lcd screen", "TOTAL"),
                                    "{0}:{1:02}".format(m, s))

    def slotFileSelected(self, index):
        if self._document:
            self._player.stop()
            files = midifiles.MidiFiles.instance(self._document)
            if files:
                files.current = index
                self.restart()

    def slotDocumentClosed(self, document):
        if document == self._document:
            self._document = None
            self._fileSelector.clear()
            self._player.stop()
            self._player.clear()
            self.updateTimeSlider()
            self._display.reset()
Ejemplo n.º 3
0
class SoundLabWindow(QtGui.QMainWindow):
    """
    Window that encapsulates the commonly operations with a
    sound lab window that contains a widget (QSignalVisualizer or descendant).
    provides usefull operations that delegates into the widget its implementation
    """

    # region Initialize

    def __init__(self, parent):
        QtGui.QMainWindow.__init__(self, parent)

        self.workSpace = Workspace()

        #  get the status bar to show messages to the user
        self.statusbar = self.statusBar()
        self.statusbar.setSizeGripEnabled(False)

        # action groups of common actions for sound lab window
        self.play_record_actions        = QActionGroup(self)
        self.widgets_visibility_actions = QActionGroup(self)
        self.zoom_actions               = QActionGroup(self)
        self.tools_actions              = QActionGroup(self)
        self.save_images_actions        = QActionGroup(self)

        # play volume bar (disabled for now)
        self.volume_bar = QSlider(QtCore.Qt.Horizontal)
        self.volume_bar.setToolTip(self.tr(u"Volume bar for Play."))
        self.volume_bar.setMaximumWidth(100)
        self.volume_bar.setRange(0, 300)
        self.volume_bar.setValue(100)
        self.volume_bar.valueChanged.connect(self.change_volume)

        # text edit for the signal name on the toolbar
        self.signalNameLineEdit = QtGui.QLineEdit(self)
        self.signalNameLineEdit.setToolTip(self.tr(u"Signal name."))
        self.signalNameLineEdit.setSizePolicy(QtGui.QSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Minimum))

        self.signalPropertiesTextLabel = QtGui.QLabel(self)
        self.signalPropertiesTextLabel.setToolTip(self.tr(u"Signal properties."))
        self.signalPropertiesTextLabel.setAlignment(QtCore.Qt.AlignRight)
        self.signalPropertiesTextLabel.setSizePolicy(QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding,
                                                                       QtGui.QSizePolicy.Minimum))

    # endregion

    def configureToolBarActionsGroups(self):
        """
        Configure the actions into groups for best visualization and
        user configuration.
        :return:
        """
        sep1, sep2, sep3, sep4 = [QtGui.QAction(self) for _ in range(4)]

        for sep in [sep1, sep2, sep3, sep4]:
            sep.setSeparator(True)

        # region play record actions
        play_record_actions_list = [self.actionPlay_Sound, self.actionPause_Sound, self.actionStop_Sound,
                                    self.actionRecord, self.actionPlayLoop, sep2]
        for act in play_record_actions_list:
            act.setActionGroup(self.play_record_actions)

        # self.toolBar.addWidget(self.volume_bar)

        # endregion

        # region widgets visibility actions
        widgets_visibility_actions_list = [self.actionOscilogram, self.actionSpectogram, self.actionCombined,
                                           sep3]

        for act in widgets_visibility_actions_list:
            act.setActionGroup(self.widgets_visibility_actions)
        # endregion

        # region zoom actions
        zoom_actions_list = [self.actionZoomIn, self.actionZoom_out,
                             self.actionZoom_out_entire_file, sep4]

        for act in zoom_actions_list:
            act.setActionGroup(self.zoom_actions)

        # endregion

        # region Save Images actions
        save_images_actions_list = [self.actionOsc_Image, self.actionSpecgram_Image,
                                    self.actionCombined_Image]

        for act in save_images_actions_list:
            act.setActionGroup(self.save_images_actions)
        # endregion

        # region Tools actions
        tools_actions_list = [self.actionZoom_Cursor, self.actionPointer_Cursor,
                              self.actionRectangular_Cursor]

        for act in tools_actions_list:
            act.setActionGroup(self.tools_actions)
        # endregion

        actions_groups = [(self.play_record_actions, self.tr(u"Play/Record")),
                          (self.zoom_actions, self.tr(u"Zoom")),
                          (self.widgets_visibility_actions, self.tr(u"Widgets Visibility"))]

        # add to the customizable sound lab toolbar
        for act in actions_groups:
            # method sig addActionGroup(actionGroup, name)
            self.toolBar.addActionGroup(act[0], act[1])

        # add the label for signal name (and edit line) that always wil be visible as an option
        # not like the other groups of actions that the user could customize visibility
        self.toolBar.addWidget(self.signalNameLineEdit)
        self.toolBar.addAction(sep1)
        self.toolBar.addWidget(self.signalPropertiesTextLabel)

    #  region Widget Tools
    @pyqtSlot()
    def on_actionZoom_Cursor_triggered(self):
        """
        Select the Zoom Tool as current working tool in the widget
        :return:
        """
        self.select_tool(self.actionZoom_Cursor, Tools.ZoomTool)

    @pyqtSlot()
    def on_actionRectangular_Cursor_triggered(self):
        """
        Select the Rectangular Cursor as current working tool in the widget
        :return:
        """
        self.select_tool(self.actionRectangular_Cursor, Tools.RectangularZoomTool)

    @pyqtSlot()
    def on_actionRectangular_Eraser_triggered(self):
        """
        Select the Rectangular Eraser as current working tool in the widget
        :return:
        """
        self.select_tool(self.actionRectangular_Eraser, Tools.RectangularEraser)

    @pyqtSlot()
    def on_actionPointer_Cursor_triggered(self):
        """
        Select the Pointer Cursor as current working tool in the widget
        :return:
        """
        self.select_tool(self.actionPointer_Cursor, Tools.PointerTool)

    def deselectToolsActions(self):
        """
        Change the checked status of all the actions tools to False
        """
        self.actionZoom_Cursor.setChecked(False)
        self.actionRectangular_Cursor.setChecked(False)
        self.actionPointer_Cursor.setChecked(False)

    def select_tool(self, tool_action, tool_type):
        """

        :param tool_action: the checkable action that handles the selection of the tool
        :param tool_type: the enum type of the tool to select in the widget
        :return:
        """
        self.deselectToolsActions()
        tool_action.setChecked(True)
        self.widget.setSelectedTool(tool_type)

    #  endregion

    #  region Save widgets Image

    @pyqtSlot()
    def on_actionOsc_Image_triggered(self):
        """
        Save to disc the image of the oscilogram graph.
        :return:
        """
        if not self.widget.visibleOscilogram:
            QtGui.QMessageBox.warning(QtGui.QMessageBox(), self.tr(u"Error"),
                                      self.tr(u"The Oscilogram plot widget is not visible.") + u"\n" + self.tr(
                                          u"You should see the data that you are going to save."))
            return

        fname = unicode(QFileDialog.getSaveFileName(self, self.tr(u"Save oscilogram graph as an Image"),
                                                u"oscilogram-Duetto-Image", u"*.jpg"))

        if fname:
            save_image(self.widget.axesOscilogram, fname)

    @pyqtSlot()
    def on_actionSpecgram_Image_triggered(self):
        """
        Save to disc the image of the spectrogram graph.
        :return:
        """
        if not self.widget.visibleSpectrogram:
            QtGui.QMessageBox.warning(QtGui.QMessageBox(), self.tr(u"Error"),
                                      self.tr(u"The Spectrogram plot widget is not visible.") + " \n" + self.tr(
                                          u"You should see the data that you are going to save."))
            return

        path = unicode(QFileDialog.getSaveFileName(self, self.tr(u"Save specgram graph as an Image"),
                                                    u"specgram-Duetto-Image", u"*.jpg"))
        save_image(self.widget.axesSpecgram, path)

    @pyqtSlot()
    def on_actionCombined_Image_triggered(self):
        """
        Save to disc the image of the both (oscilogram and spectrogram)
        visualization graphs.
        :return:
        """
        if not self.widget.visibleOscilogram or not self.widget.visibleSpectrogram:
            QtGui.QMessageBox.warning(QtGui.QMessageBox(), self.tr(u"Error"),
                                      self.tr(u"One of the plot widgets is not visible.") + " \n" + self.tr(
                                          u"You should see the data that you are going to save."))
            return

        path = unicode(QFileDialog.getSaveFileName(self, self.tr(u"Save graph as an Image"), u"Graph Image", u"*.jpg"))
        save_image(self.widget, path)

    #  endregion

    # region Zoom
    # delegate in the widget the zoom interaction with the signal
    @QtCore.pyqtSlot()
    def on_actionZoomIn_triggered(self):
        self.widget.zoomIn()

    @QtCore.pyqtSlot()
    def on_actionZoom_out_triggered(self):
        self.widget.zoomOut()

    @QtCore.pyqtSlot()
    def on_actionZoom_out_entire_file_triggered(self):
        self.widget.zoomNone()

    # endregion

    #  region Widgets And Window Visibility

    @pyqtSlot()
    def on_actionFull_Screen_triggered(self):
        """
        Action that switch the window visualization state between
        Full Screen and Normal
        :return:
        """
        if self.actionFull_Screen.isChecked():
            self.showFullScreen()
        else:
            self.showNormal()

    @pyqtSlot()
    def on_actionCombined_triggered(self):
        """
        Shows both axes visualization oscilogram and spectrogram.
        :return:
        """
        self.changeWidgetsVisibility(True, True)

    @pyqtSlot()
    def on_actionSpectogram_triggered(self):
        """
        Shows the spectrogram visualization graph only.
        :return:
        """
        self.changeWidgetsVisibility(False, True)

    @pyqtSlot()
    def on_actionOscilogram_triggered(self):
        """
        Shows the oscilogram visualization graph only.
        :return:
        """
        self.changeWidgetsVisibility(True, False)

    def changeWidgetsVisibility(self, visibleOscilogram=True, visibleSpectrogram=True):
        """
        Method that change the visibility of the widgets
        oscilogram and spectrogram on the main widget
        :param visibleOscilogram:  Visibility of the oscilogram
        :param visibleSpectrogram: Visibility of the spectrogram
        :return:
        """
        self.widget.visibleOscilogram = visibleOscilogram
        self.widget.visibleSpectrogram = visibleSpectrogram

        # udpate the workspace
        self.workSpace.visibleOscilogram = visibleOscilogram
        self.workSpace.visibleSpectrogram = visibleSpectrogram

        self.widget.graph()

    # endregion

    #  region Play, Pause, Stop, Record
    # delegate in the widget reproduction actions
    def change_volume(self, volume):
        # change volume in the player of the widget
        if self.widget:
            self.widget.change_volume(volume)

        self.update_status_bar(self.tr(u"The volume has been changed to "+unicode(volume) + u"%."), 1000)

    @pyqtSlot()
    def on_actionPlay_Sound_triggered(self):
        try:
            self.widget.play()

        except Exception as ex:
            QtGui.QMessageBox.warning(QtGui.QMessageBox(), self.tr(u"Error"),
                                      self.tr(u"There is no selected audio input "
                                              u"device or the selected is unavailable"))

    @pyqtSlot()
    def on_actionPlayLoop_triggered(self):
        self.widget.setPlayLoopEnabled(self.actionPlayLoop.isChecked())

    @pyqtSlot()
    def on_actionStop_Sound_triggered(self):
        self.widget.stop()

        # if previous status was recording the length of signal has changed and must be updated
        self.updateSignalPropertiesLabel()

    @pyqtSlot()
    def on_actionPause_Sound_triggered(self):
        self.widget.pause()

    @pyqtSlot()
    def on_actionSwitchPlayStatus_triggered(self):
        """
        Change the play status of the signal from play-pause and vice versa
        :return:
        """
        self.widget.switchPlayStatus()

    # endregion

    # region Edition and Processing Methods

    # region Undo Redo

    @pyqtSlot()
    def on_actionUndo_triggered(self):
        self.widget.undo()
        self.updateSignalPropertiesLabel()

    @pyqtSlot()
    def on_actionRedo_triggered(self):
        self.widget.redo()
        self.updateSignalPropertiesLabel()

    # endregion

    #  region Cut, Copy, Paste
    @pyqtSlot()
    def on_actionCut_triggered(self):
        self.widget.cut()
        self.updateSignalPropertiesLabel()

    @pyqtSlot()
    def on_actionCopy_triggered(self):
        self.widget.copy()

    @pyqtSlot()
    def on_actionPaste_triggered(self):
        self.widget.paste()
        self.updateSignalPropertiesLabel()

    #  endregion

    # endregion

    def update_status_bar(self, line, time_ms=None):
        """
        Set a new message in the status bar of the window.
        :type time: the time that the line message wouold be visible in status bar.
        :param line: string with the line to show in the status bar
        """
        time_ms = 1500 if time_ms is None else time_ms

        self.statusbar.showMessage(line, time_ms)

    def updateSignalPropertiesLabel(self, signal = None):
        """
        Updates the text of the current signal properties in toolbar.
        :return:
        """
        signal = self.widget.signal if signal is None else signal

        # action signal is a place in the tool bar to show the current signal name
        self.signalNameLineEdit.setText(signal.name)

        sr, bit_depth, channels = signal.samplingRate, signal.bitDepth, signal.channelCount

        properties = u"    " + \
                     u" <b>" + self.tr(u"Sampling Rate: ") + u"</b>" + unicode(sr) + u"  " + \
                     u" <b>" + self.tr(u"Bit Depth: ") + u"</b>" + unicode(bit_depth) + u"  " + \
                     u" <b>" + self.tr(u"Channels: ") + u"</b>" + unicode(channels) + u"  " + \
                     u" <b>" + self.tr(u"Duration(s): ") + u"</b>" + unicode(round(signal.duration, DECIMAL_PLACES)) + \
                     u"    "

        self.signalPropertiesTextLabel.setText(properties)
class MyMainWindow(QMainWindow):
    ' Main Window '
    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()

    def play(self, index):
        ' play with delay '
        if not self.media:
            self.media = Phonon.MediaObject(self)
            audioOutput = Phonon.AudioOutput(Phonon.MusicCategory, self)
            Phonon.createPath(self.media, audioOutput)
        self.media.setCurrentSource(Phonon.MediaSource(
            self.model.filePath(index)))
        self.media.play()

    def end(self):
        ' kill it with fire '
        print((' INFO: Stoping Processes at {}'.format(str(datetime.now()))))
        self.process1.terminate()
        self.process2.terminate()
        self.feedback.setText('''
            <h5>Errors for RECORDER QProcess 1:</h5>{}<hr>
            <h5>Errors for ENCODER QProcess 2:</h5>{}<hr>
            <h5>Output for RECORDER QProcess 1:</h5>{}<hr>
            <h5>Output for ENCODER QProcess 2:</h5>{}<hr>
            '''.format(self.process1.readAllStandardError(),
                       self.process2.readAllStandardError(),
                       self.process1.readAllStandardOutput(),
                       self.process2.readAllStandardOutput(),
        ))

    def killer(self):
        ' kill -9 '
        QMessageBox.information(self.mainwidget, __doc__,
            ' KILL -9 was sent to the multi-process backend ! ')
        self.process1.kill()
        self.process2.kill()

    def go(self):
        ' run timeout re-starting timers '
        self.timerFirst.start(int(self.slider.value()) * 60 * 1000 + 2000)
        self.timerSecond.start(int(self.slider.value()) * 60 * 1000 + 2010)
        self.run()

    def run(self):
        ' run forest run '
        print((' INFO: Working at {}'.format(str(datetime.now()))))

        chnl = 1 if self.combo3.currentText() == 'MONO' else 2
        print((' INFO: Using {} Channels . . . '.format(chnl)))

        btrt = int(self.combo4.currentText())
        print((' INFO: Using {} Hz per Second . . . '.format(btrt)))

        threshold = int(self.dial.value())
        print((' INFO: Using Thresold of {} . . . '.format(threshold)))

        print((' INFO: Using Recording time of {}'.format(self.slider.value())))

        frmt = str(self.combo0.currentText()).strip()
        print((' INFO: Using Recording quality of {} ...'.format(frmt)))

        qlt = str(self.combo1.currentText()).strip()
        print((' INFO: Using Recording quality of {} ...'.format(qlt)))

        prio = str(self.combo5.currentText()).strip()
        print((' INFO: Using CPU Priority of {} ...'.format(prio)))

        downmix = '--downmix ' if self.chckbx1.isChecked() is True else ''
        print((' INFO: Using Downmix is {} ...'.format(downmix)))

        aut = '-a ' + getuser() if self.chckbx3.isChecked() is True else ''
        print((' INFO: The Author Artist of this sound is: {}'.format(aut)))

        T = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
        tim = '--date {} '.format(T) if self.chckbx2.isChecked() is True else ''
        print((' INFO: The Date and Time of this sound is: {}'.format(tim)))

        vol = ' --disable-softvol' if self.chckbx0.isChecked() is True else ''
        print((' INFO: Software based Volume Control is: {}'.format(vol)))

        # make base directory
        try:
            mkdir(self.base)
            print((' INFO: Base Directory path created {}'.format(self.base)))
        except OSError:
            print((' INFO: Base Directory already exist {}'.format(self.base)))
        except:
            print((' ERROR: Can not create Directory ?, {}'.format(self.base)))

        # make directory tree
        try:
            for dr in range(1, 13):
                mkdir(path.abspath(path.join(self.base, str(dr))))
                print((' INFO:Directory created {}/{}'.format(self.base, dr)))
        except OSError:
            print((' INFO: Directory already exist {}/1,12'.format(self.base)))
        except:
            print((' ERROR: Cant create Directory?, {}/1,12'.format(self.base)))

        # make new filename
        flnm = path.abspath(path.join(self.base, str(datetime.now().month),
                   datetime.now().strftime("%Y-%m-%d_%H:%M:%S.ogg")))
        self.actual_file = flnm
        print((' INFO: Recording on the file {}'.format(flnm)))

        # make custom commands
        cmd1 = self.cmd1.format(n=prio, f=frmt, c=chnl, b=btrt, v=vol)
        cmd2 = self.cmd2.format(c=chnl, b=btrt, q=qlt,
                                d=downmix, o=flnm, a=aut, t=tim)
        print((cmd1, cmd2))
        #  multiprocess recording loop pipe
        self.process1 = QProcess(self)
        self.process2 = QProcess(self)
        self.process1.setStandardOutputProcess(self.process2)
        self.process1.start(cmd1)
        if not self.process1.waitForStarted():
            print((" ERROR: RECORDER QProcess 1 Failed: \n {}   ".format(cmd1)))
        self.process2.start(cmd2)
        if not self.process2.waitForStarted():
            print((" ERROR: ENCODER QProcess 2 Failed: \n   {} ".format(cmd2)))
        self.nepomuk_set(flnm, 'testigo', 'testigo', 'AutoTag by Cinta-Testigo')

    def spectro(self):
        ' spectrometer '
        wid = self.spec.size().width()
        hei = self.spec.size().height()
        command = self.cmd3.format(o=self.actual_file, x=wid, y=hei)
        print(' INFO: Spectrometer is deleting OLD .ogg.png Files on target ')
        call('rm --verbose --force {}/*/*.ogg.png'.format(self.base), shell=1)
        print(' INFO: Spectrometer finished Deleting Files, Starting Render ')
        call(command, shell=True)
        print((''' INFO: Spectrometer finished Rendering Sound using:
               {}{}   OutPut: {}'''.format(command, linesep, self.actual_file)))
        self.spec.setIcon(QIcon('{o}.png'.format(o=self.actual_file)))
        self.spec.setIconSize(QSize(wid, hei))
        self.spec.resize(wid, hei)

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

    def paintEvent(self, event):
        'Paint semi-transparent background, animated pattern, background text'
        QWidget.paintEvent(self, event)
        # make a painter
        p = QPainter(self)
        p.setRenderHint(QPainter.TextAntialiasing)
        p.setRenderHint(QPainter.HighQualityAntialiasing)
        # fill a rectangle with transparent painting
        p.fillRect(event.rect(), Qt.transparent)
        # animated random dots background pattern
        for i in range(4096):
            x = randint(9, self.size().width() - 9)
            y = randint(9, self.size().height() - 9)
            p.setPen(QPen(QColor(randint(200, 255), randint(200, 255), 255), 1))
            p.drawPoint(x, y)
        # set pen to use white color
        p.setPen(QPen(QColor(randint(9, 255), randint(9, 255), 255), 1))
        # Rotate painter 45 Degree
        p.rotate(35)
        # Set painter Font for text
        p.setFont(QFont('Ubuntu', 300))
        # draw the background text, with antialiasing
        p.drawText(99, 199, "Radio")
        # Rotate -45 the QPen back !
        p.rotate(-35)
        # set the pen to no pen
        p.setPen(Qt.NoPen)
        # Background Color
        p.setBrush(QColor(0, 0, 0))
        # Background Opacity
        p.setOpacity(0.75)
        # Background Rounded Borders
        p.drawRoundedRect(self.rect(), 50, 50)
        # finalize the painter
        p.end()

    def seTitle(self):
        ' set the title of the main window '
        dialog = QDialog(self)
        textEditInput = QLineEdit(' Type Title Here ')
        ok = QPushButton(' O K ')
        ok.clicked.connect(lambda: self.setWindowTitle(textEditInput.text()))
        ly = QVBoxLayout()
        [ly.addWidget(wdgt) for wdgt in (QLabel('Title:'), textEditInput, ok)]
        dialog.setLayout(ly)
        dialog.exec_()

    def timedate(self):
        ' get the time and date '
        dialog = QDialog(self)
        clock = QLCDNumber()
        clock.setNumDigits(24)
        timer = QTimer()
        timer.timeout.connect(lambda: clock.display(
            datetime.now().strftime("%d-%m-%Y %H:%M:%S %p")))
        timer.start(1000)
        clock.setToolTip(datetime.now().strftime("%c %x"))
        ok = QPushButton(' O K ')
        ok.clicked.connect(dialog.close)
        ly = QVBoxLayout()
        [ly.addWidget(wdgt) for wdgt in (QCalendarWidget(), clock, ok)]
        dialog.setLayout(ly)
        dialog.exec_()

    def closeEvent(self, event):
        ' Ask to Quit '
        if QMessageBox.question(self, ' Close ', ' Quit ? ',
           QMessageBox.Yes | QMessageBox.No, QMessageBox.No) == QMessageBox.Yes:
            event.accept()
        else:
            event.ignore()

    def center(self):
        ' Center and resize the window '
        self.showNormal()
        self.resize(QDesktopWidget().screenGeometry().width() // 1.25,
                    QDesktopWidget().screenGeometry().height() // 1.25)
        qr = self.frameGeometry()
        qr.moveCenter(QDesktopWidget().availableGeometry().center())
        self.move(qr.topLeft())

    def nepomuk_set(self, file_tag=None, __tag='', _label='', _description=''):
        ' Quick and Easy Nepomuk Taggify for Files '
        print((''' INFO: Semantic Desktop Experience is Tagging Files :
              {}, {}, {}, {})'''.format(file_tag, __tag, _label, _description)))
        if Nepomuk.ResourceManager.instance().init() is 0:
            fle = Nepomuk.Resource(KUrl(QFileInfo(file_tag).absoluteFilePath()))
            _tag = Nepomuk.Tag(__tag)
            _tag.setLabel(_label)
            fle.addTag(_tag)
            fle.setDescription(_description)
            print(([str(a.label()) for a in fle.tags()], fle.description()))
            return ([str(a.label()) for a in fle.tags()], fle.description())
        else:
            print(" ERROR: FAIL: Nepomuk is not running ! ")

    def nepomuk_get(self, query_to_search):
        ' Quick and Easy Nepomuk Query for Files '
        print((''' INFO: Semantic Desktop Experience is Quering Files :
              {} '''.format(query_to_search)))
        results = []
        nepo = Nepomuk.Query.QueryServiceClient()
        nepo.desktopQuery("hasTag:{}".format(query_to_search))

        def _query(data):
            ''' ('filename.ext', 'file description', ['list', 'of', 'tags']) '''
            results.append(([str(a.resource().genericLabel()) for a in data][0],
                            [str(a.resource().description()) for a in data][0],
            [str(a.label()) for a in iter([a.resource().tags() for a in data][0]
            )]))
        nepo.newEntries.connect(_query)

        def _end():
            '''
            [  ('filename.ext', 'file description', ['list', 'of', 'tags']),
               ('filename.ext', 'file description', ['list', 'of', 'tags']),
               ('filename.ext', 'file description', ['list', 'of', 'tags'])  ]
            '''
            nepo.newEntries.disconnect
            print(results)
            return results
        nepo.finishedListing.connect(_end)
Ejemplo n.º 5
0
class Slider(QWidget):
    def __init__(
        self,
        caption,
        default_value,
        minimum_value=1,
        maximum_value=60,
        single_step=1,
        page_step=6,
        caption_size=None,
        unit="",
        time=False,
        tooltip="",
    ):
        QWidget.__init__(self)

        self.value = default_value
        self.unit = unit
        self.time = time

        description = QLabel(caption)
        description.setWordWrap(True)
        description.setToolTip(tooltip)
        if caption_size:
            description.setMaximumWidth(caption_size)

        self.slider = QSlider(Qt.Horizontal)
        self.slider.setMaximum(maximum_value)
        self.slider.setMinimum(minimum_value)
        self.slider.setSingleStep(single_step)
        self.slider.setPageStep(page_step)
        self.slider.setToolTip(tooltip)
        # self.slider.setTickInterval(2)
        # self.slider.setTickPosition(QSlider.TicksBelow)
        self.slider.valueChanged.connect(self.__on_change)

        self.value_label = QLabel()

        hbox = QHBoxLayout()
        hbox.addWidget(description)
        hbox.addWidget(self.slider)
        hbox.addWidget(self.value_label)
        hbox.setMargin(0)
        self.setLayout(hbox)
        self.setContentsMargins(5, 0, 5, 0)
        self.slider.setValue(self.value)
        self.__on_change(self.value)

    def __on_change(self, value):
        # FIXME: Fill with spaces to reach the maximum length
        self.value = value
        unit = self.unit
        if self.time:
            minutes = timedelta(minutes=self.value)
            date = datetime(1, 1, 1) + minutes
            text = "%02dh %02dm" % (date.hour, date.minute)
        else:
            text = "%s %s" % (self.value, self.unit)
        self.value_label.setText(text)

    def get_value(self):
        return int(self.slider.value())
Ejemplo n.º 6
0
class Widget(QWidget):
    def __init__(self, dockwidget):
        super(Widget, self).__init__(dockwidget)
        self._document = None
        self._fileSelector = QComboBox(editable=True, insertPolicy=QComboBox.NoInsert)
        widgets.drag.ComboDrag(self._fileSelector).role = Qt.UserRole
        self._fileSelector.lineEdit().setReadOnly(True)
        self._fileSelector.lineEdit().setFocusPolicy(Qt.NoFocus)
        self._stopButton = QToolButton()
        self._playButton = QToolButton()
        self._timeSlider = QSlider(Qt.Horizontal, tracking=False,
            singleStep=500, pageStep=5000, invertedControls=True)
        self._display = Display()
        self._tempoFactor = QSlider(Qt.Vertical, minimum=-50, maximum=50,
            singleStep=1, pageStep=5)
        
        grid = QGridLayout(spacing=0)
        self.setLayout(grid)
        
        grid.addWidget(self._fileSelector, 0, 0, 1, 3)
        grid.addWidget(self._stopButton, 1, 0)
        grid.addWidget(self._playButton, 1, 1)
        grid.addWidget(self._timeSlider, 1, 2)
        grid.addWidget(self._display, 2, 0, 1, 3)
        grid.addWidget(self._tempoFactor, 0, 3, 3, 1)
        
        # size policy of combo
        p = self._fileSelector.sizePolicy()
        p.setHorizontalPolicy(QSizePolicy.Ignored)
        self._fileSelector.setSizePolicy(p)
        
        # size policy of combo popup
        p = self._fileSelector.view().sizePolicy()
        p.setHorizontalPolicy(QSizePolicy.MinimumExpanding)
        self._fileSelector.view().setSizePolicy(p)

        self._player = player.Player()
        self._outputCloseTimer = QTimer(interval=60000, singleShot=True,
            timeout=self.closeOutput)
        self._timeSliderTicker = QTimer(interval=200, timeout=self.updateTimeSlider)
        self._fileSelector.activated[int].connect(self.slotFileSelected)
        self._tempoFactor.valueChanged.connect(self.slotTempoChanged)
        self._timeSlider.valueChanged.connect(self.slotTimeSliderChanged)
        self._timeSlider.sliderMoved.connect(self.slotTimeSliderMoved)
        self._player.beat.connect(self.updateDisplayBeat)
        self._player.time.connect(self.updateDisplayTime)
        self._player.stateChanged.connect(self.slotPlayerStateChanged)
        self.slotPlayerStateChanged(False)
        dockwidget.mainwindow().currentDocumentChanged.connect(self.loadResults)
        app.documentLoaded.connect(self.slotUpdatedFiles)
        app.jobFinished.connect(self.slotUpdatedFiles)
        app.aboutToQuit.connect(self.stop)
        midihub.aboutToRestart.connect(self.slotAboutToRestart)
        midihub.settingsChanged.connect(self.clearMidiSettings, -100)
        midihub.settingsChanged.connect(self.readMidiSettings)
        app.documentClosed.connect(self.slotDocumentClosed)
        app.translateUI(self)
        self.readMidiSettings()
        d = dockwidget.mainwindow().currentDocument()
        if d:
            self.loadResults(d)

    def translateUI(self):
        self._tempoFactor.setToolTip(_("Tempo"))
    
    def slotAboutToRestart(self):
        self.stop()
        self._player.set_output(None)
    
    def clearMidiSettings(self):
        """Called first when settings are changed."""
        self.stop()
        self._outputCloseTimer.stop()
        self._player.set_output(None)
        
    def readMidiSettings(self):
        """Called after clearMidiSettings(), and on first init."""
        pass
            
    def openOutput(self):
        """Called when playing starts. Ensures an output port is opened."""
        self._outputCloseTimer.stop()
        if not self._player.output():
            p = QSettings().value("midi/player/output_port", midihub.default_output(), type(""))
            o = midihub.output_by_name(p)
            if o:
                self._player.set_output(output.Output(o))
    
    def closeOutput(self):
        """Called when the output close timer fires. Closes the output."""
        self._player.set_output(None)
        
    def slotPlayerStateChanged(self, playing):
        ac = self.parentWidget().actionCollection
        # setDefaultAction also adds the action
        for b in self._stopButton, self._playButton:
            while b.actions():
                b.removeAction(b.actions()[0])
        if playing:
            self._timeSliderTicker.start()
            self._stopButton.setDefaultAction(ac.midi_stop)
            self._playButton.setDefaultAction(ac.midi_pause)
        else:
            self._timeSliderTicker.stop()
            self.updateTimeSlider()
            self._stopButton.setDefaultAction(ac.midi_restart)
            self._playButton.setDefaultAction(ac.midi_play)
            # close the output if the preference is set
            if QSettings().value("midi/close_outputs", False, bool):
                self._outputCloseTimer.start()
        
    def play(self):
        """Starts the MIDI player, opening an output if necessary."""
        if not self._player.is_playing() and not self._player.has_events():
            self.restart()
        self.openOutput()
        if not self._player.output():
            self._display.statusMessage(_("No output found!"))
        self._player.start()
    
    def stop(self):
        """Stops the MIDI player."""
        self._player.stop()
    
    def restart(self):
        """Restarts the MIDI player.
        
        If another file is in the file selector, or the file was updated,
        the new file is loaded.
        
        """
        self._player.seek(0)
        self.updateTimeSlider()
        self._display.reset()
        if self._document:
            files = midifiles.MidiFiles.instance(self._document)
            index = self._fileSelector.currentIndex()
            if files and (files.song(index) is not self._player.song()):
                self.loadSong(index)
        
    def slotTempoChanged(self, value):
        """Called when the user drags the tempo."""
        # convert -50 to 50 to 0.5 to 2.0
        factor = 2 ** (value / 50.0)
        self._player.set_tempo_factor(factor)
        self._display.setTempo("{0}%".format(int(factor * 100)))
    
    def slotTimeSliderChanged(self, value):
        self._player.seek(value)
        self._display.setTime(value)
        if self._player.song():
            self._display.setBeat(*self._player.song().beat(value)[1:])
    
    def slotTimeSliderMoved(self, value):
        self._display.setTime(value)
        if self._player.song():
            self._display.setBeat(*self._player.song().beat(value)[1:])
    
    def updateTimeSlider(self):
        if not self._timeSlider.isSliderDown():
            with qutil.signalsBlocked(self._timeSlider):
                self._timeSlider.setMaximum(self._player.total_time())
                self._timeSlider.setValue(self._player.current_time())

    def updateDisplayBeat(self, measnum, beat, num, den):
        if not self._timeSlider.isSliderDown():
            self._display.setBeat(measnum, beat, num, den)
    
    def updateDisplayTime(self, time):
        if not self._timeSlider.isSliderDown():
            self._display.setTime(time)
    
    def slotUpdatedFiles(self, document):
        """Called when there are new MIDI files."""
        if document == self.parentWidget().mainwindow().currentDocument():
            self.loadResults(document)
    
    def loadResults(self, document):
        self._document = document
        files = midifiles.MidiFiles.instance(document)
        self._fileSelector.setModel(files.model())
        if files:
            self._fileSelector.setCurrentIndex(files.current)
            if not self._player.is_playing():
                self.loadSong(files.current)
    
    def loadSong(self, index):
        files = midifiles.MidiFiles.instance(self._document)
        self._player.set_song(files.song(index))
        m, s = divmod(self._player.total_time() // 1000, 60)
        name = self._fileSelector.currentText()
        self.updateTimeSlider()
        self._display.reset()
        self._display.statusMessage(
            _("midi lcd screen", "LOADED"), name,
            _("midi lcd screen", "TOTAL"), "{0}:{1:02}".format(m, s))
    
    def slotFileSelected(self, index):
        if self._document:
            self._player.stop()
            files = midifiles.MidiFiles.instance(self._document)
            if files:
                files.current = index
                self.restart()
    
    def slotDocumentClosed(self, document):
        if document == self._document:
            self._document = None
            self._fileSelector.clear()
            self._player.stop()
            self._player.clear()
            self.updateTimeSlider()
            self._display.reset()
Ejemplo n.º 7
0
class filexplorerPluginMain(plugin.Plugin):
    ' main class for plugin '
    def initialize(self, *args, **kwargs):
        ' class init '
        global CONFIG_DIR
        ec = ExplorerContainer()
        super(filexplorerPluginMain, self).initialize(*args, **kwargs)

        self.dock = QDockWidget()
        self.dock.setAllowedAreas(Qt.LeftDockWidgetArea |
                                  Qt.RightDockWidgetArea)
        self.dock.setFeatures(QDockWidget.DockWidgetFloatable |
                              QDockWidget.DockWidgetMovable)
        self.dock.setWindowTitle("fileXplorer")
        self.dock.setStyleSheet('QDockWidget::title { text-align: center; }')

        # search for the truth
        self.srch = QLineEdit()
        #self.srch.resize(self.srch.size().height(), self.dock.size().width())
        self.srch.setPlaceholderText(' Search for Python files Local or PyPI ')
        self.srch.returnPressed.connect(self.search)

        # Disk Usage Bar
        self.hdbar = QProgressBar()
        if sys.platform != 'win32':
            self.hdbar.setMaximum(statvfs(HOME).f_blocks *
                statvfs(HOME).f_frsize / 1024 / 1024 / 1024)
            self.hdbar.setValue(statvfs(HOME).f_bfree *
                statvfs(HOME).f_frsize / 1024 / 1024 / 1024)
        self.hdbar.setToolTip(str(self.hdbar.value()) + '% Total Disk Use ')
        #self.hdbar.setStyleSheet('''QProgressBar{background-color:
        #QLinearGradient(spread:pad,x1:0,y1:0,x2:1,y2:1,stop:0 rgba(255,0,0,99),
        #stop:1 rgba(9,255,9,200));color:#fff;border:none;border-radius:9px;}
        #QProgressBar::chunk{background-color:QLinearGradient(spread:pad,y1:0,
        #x1:0,y2:1,x2:0.27,stop:0 rgb(0,0,0),stop:1 rgb(9,99,255));padding:0;
        #border:none;border-radius:9px;height:9px;margin:1px;}''')

        self.model = QDirModel()
        self.fileView = QColumnView(self.dock)
        self.fileView.setAlternatingRowColors(True)
        # self.fileView.setFont(QFont(self.fileView.font().setBold(True)))
        self.fileView.setIconSize(QSize(32, 32))
        self.fileView.setModel(self.model)
        self.fileView.updatePreviewWidget.connect(self.runfile)

        self.sli = QSlider()
        self.sli.setRange(16, 128)
        self.sli.setValue(32)
        self.sli.setToolTip('Icon Size: 32 px. Move Slider to change.')
        self.sli.setOrientation(Qt.Horizontal)
        self.sli.valueChanged.connect(lambda: self.fileView.setIconSize(
            QSize(self.sli.value(), self.sli.value())))
        self.sli.sliderReleased.connect(lambda:
            self.sli.setToolTip('Icon Size: ' + str(self.sli.value())))

        class TransientWidget(QWidget):
            ' persistant widget thingy '
            def __init__(self, widget_list):
                ' init sub class '
                super(TransientWidget, self).__init__()
                vbox = QVBoxLayout(self)
                for each_widget in widget_list:
                    vbox.addWidget(each_widget)

        tw = TransientWidget((self.srch, self.dock, self.sli, self.hdbar))
        ec.addTab(tw, "fileXplorer")

        ####

        self.process = QProcess()
        self.process.finished.connect(self.processFinished)

        self.preview = QLabel(self.fileView)
        self.preview.setTextFormat(0)
        self.preview.setStyleSheet('QLabel{font-size:9px;}')
        self.preview.setAutoFillBackground(True)
        self.fileView.setPreviewWidget(self.preview)
        self.dock.setWidget(self.fileView)

        # take a shot
        self.pic = QAction(QIcon.fromTheme("camera-photo"), 'Screenshot', self)
        self.pic.triggered.connect(lambda: QPixmap.grabWindow(
            QApplication.desktop().winId()).save(QFileDialog.getSaveFileName(
            self.dock, " Save Screenshot As ... ", HOME, ';;(*.png)')))

        # copy time
        self.tim = QAction(QIcon.fromTheme("user-away"),
                           'Date and Time to Clipboard', self)
        self.tim.triggered.connect(lambda: QApplication.clipboard().setText(
            datetime.now().strftime(" %A %B %d-%m-%Y %H:%M:%S %p ")))

        # color chooser
        self.cl = QAction(QIcon.fromTheme("applications-graphics"),
                          'Color Chooser to Clipboard', self)
        self.cl.triggered.connect(lambda: QApplication.clipboard().setText(
            '{}'.format(QColorDialog.getColor().name())))

        # icon chooser
        self.icn = QAction(QIcon.fromTheme("insert-image"),
                          'Icon Chooser to Clipboard', self)
        self.icn.triggered.connect(self.iconChooser)

        # tool bar with actions
        QToolBar(self.dock).addActions((self.cl, self.icn, self.tim, self.pic))

        self.textBrowser = QTextBrowser(self.dock)
        self.textBrowser.setAutoFillBackground(True)
        self.textBrowser.setGeometry(self.dock.geometry())
        self.textBrowser.hide()

    def processFinished(self):
        ' print info of finished processes '
        print(" INFO: OK: QProcess finished . . . ")

    def search(self):
        ' function to search python files '
        # get search results of python filenames local or remote
        pypi_url = 'http://pypi.python.org/pypi'
        # pypi query
        pypi = xmlrpclib.ServerProxy(pypi_url, transport=ProxyTransport())
        try:
            pypi_query = pypi.search({'name': str(self.srch.text()).lower()})
            pypi_fls = list(set(['pypi.python.org/pypi/' + a['name'] +
                   ' | pip install ' + a['name'] for a in pypi_query]))
        except:
            pypi_fls = '<b> ERROR: Internet not available! ಠ_ಠ </b>'
        s_out = ('<br> <br> <br> <h3> Search Local Python files: </h3> <hr> ' +
        # Jedi list comprehension for LOCAL search
        str(["{}/{}".format(root, f) for root, f in list(itertools.chain(*
            [list(itertools.product([root], files))
            for root, dirs, files in walk(str(
            QFileDialog.getExistingDirectory(self.dock,
            'Open Directory to Search', path.expanduser("~"))))]))
            if f.endswith(('.py', '.pyw', '.pth')) and not f.startswith('.')
            and str(self.srch.text()).lower().strip() in f]
        ).replace(',', '<br>') + '<hr><h3> Search PyPI Python files: </h3>' +
        # wraped pypi query REMOTE search
        str(pypi_fls).replace(',', '<br>') + '<hr>Auto-Proxy:ON,DoNotTrack:ON')
        # print(s_out)
        try:
            call('notify-send fileXplorer Searching...', shell=True)
        except:
            pass
        self.srch.clear()
        self.textBrowser.setGeometry(self.dock.geometry())
        self.textBrowser.setHtml(s_out)
        self.textBrowser.show()
        tmr = QTimer(self.fileView)
        tmr.timeout.connect(self.textBrowser.hide)
        tmr.start(20000)

    def iconChooser(self):
        ' Choose a Icon and copy it to clipboard '
        #
        from .std_icon_naming import std_icon_naming as a
        #
        prv = QDialog(self.dock)
        prv.setWindowFlags(Qt.FramelessWindowHint)
        prv.setAutoFillBackground(True)
        prv.setGeometry(self.fileView.geometry())
        table = QTableWidget(prv)
        table.setColumnCount(1)
        table.setRowCount(len(a))
        table.verticalHeader().setVisible(True)
        table.horizontalHeader().setVisible(False)
        table.setShowGrid(True)
        table.setIconSize(QSize(128, 128))
        for index, icon in enumerate(a):
            item = QTableWidgetItem(QIcon.fromTheme(icon), '')
            # item.setData(Qt.UserRole, '')
            item.setToolTip(icon)
            table.setItem(index, 0, item)
        table.clicked.connect(lambda: QApplication.clipboard().setText(
          'QtGui.QIcon.fromTheme("{}")'.format(table.currentItem().toolTip())))
        table.doubleClicked.connect(prv.close)
        table.resizeColumnsToContents()
        table.resizeRowsToContents()
        QLabel('<h3> <br> 1 Click Copy, 2 Clicks Close </h3>', table)
        table.resize(prv.size())
        prv.exec_()

    def runfile(self, index):
        ' run the choosed file '
        s = str(file(self.model.filePath(index), 'r').read().strip())
        f = str(self.model.filePath(index))
        # ctime is NOT crossplatform,metadata change on *nix,creation on Window
        # http://docs.python.org/library/os.path.html#os.path.getctime
        m = ''.join((f, N, str(path.getsize(f) / 1024), ' Kilobytes', N,
            str(len(file(f, 'r').readlines())), ' Lines', N,
            str(len(s.replace(N, ''))), ' Characters', N,
            str(len([a for a in sub('[^a-zA-Z0-9 ]', '', s).split(' ')
                if a != ''])), ' Words', N,
            str(len([a for a in s if a in punctuation])), ' Punctuation', N,
            oct(stat(f).st_mode)[-3:], ' Permissions', N,
            time.ctime(path.getatime(f)), ' Accessed', N,
            time.ctime(path.getmtime(f)), ' Modified', N,
            'Owner: ', str(self.model.fileInfo(index).owner()), N,
            'Is Writable: ', str(self.model.fileInfo(index).isWritable()), N,
            'Is Executable: ', str(self.model.fileInfo(index).isExecutable()),
            N, 'Is Hidden: ', str(self.model.fileInfo(index).isHidden()), N,
            'Is SymLink: ', str(self.model.fileInfo(index).isSymLink()), N,
            'File Extension: ', str(self.model.fileInfo(index).suffix())
        ))
        #print(m)
        self.preview.setToolTip(m)
        self.preview.setText(s)
        self.preview.resize(self.preview.size().width(),
                            self.dock.size().height())
        self.process.start('xdg-open {}'.format(f))
        if not self.process.waitForStarted():
            print((" ERROR: Process {} Failed ! ".format(str(f))))
            return