Example #1
0
 def connect(self):
     """Connect to the selected log file tailer."""
     try:
         cmd_tmpl = self.cmd_tmpls[self.filename]
     except (KeyError, TypeError):
         cmd_tmpl = None
     self.t = Tailer(self.logview, self.filename, cmd_tmpl=cmd_tmpl)
     self.t.start()
Example #2
0
 def connect(self):
     """Run the tailer command."""
     cmd = self.cmd_tmpl % {'rotation': self.rotation,
                            'suite_name': self.suite_name,
                            'suite_log': self.suite_log}
     self.t = Tailer(
         self.logview, cmd,
         filters=[f for f in [self.task_filter, self.custom_filter] if f])
     self.t.start()
Example #3
0
 def run(self):
     proc = Popen(
         self.command, stdin=open(os.devnull), stdout=self.stdoutfile,
         stderr=STDOUT, shell=True)
     self.proc = proc
     gobject.timeout_add(40, self.pulse_proc_progress)
     tail_cmd_tmpl = glbl_cfg().get_host_item("tail command template")
     tail_cmd = tail_cmd_tmpl % {'filename': self.stdoutfile.name}
     self.stdout_updater = Tailer(self.textview, tail_cmd, pollable=proc)
     self.stdout_updater.start()
Example #4
0
 def update_view(self):
     self.t.stop()
     logbuffer = self.logview.get_buffer()
     s, e = logbuffer.get_bounds()
     self.reset_logbuffer()
     logbuffer.delete(s, e)
     self.log_label.set_text(self.path())
     self.t = Tailer(
         self.logview, self.path(),
         filters=[f for f in [self.task_filter, self.custom_filter] if f])
     self.t.start()
Example #5
0
 def connect(self):
     """Connect to the selected log file tailer."""
     cmd = self.cmd_tmpl % {
         'subnum': self.nsubmit,
         'suite_name': self.suite_name,
         'task_id': self.task_id,
         'job_log': self.choice
     }
     self.log_label.set_text(self.choice)
     self.t = Tailer(self.logview, cmd)
     self.t.start()
Example #6
0
 def run(self):
     proc = None
     if not self.ignore_command:
         proc = subprocess.Popen(
             self.command, stdout=self.stdout, stderr=subprocess.STDOUT,
             shell=True)
         self.proc = proc
         gobject.timeout_add(40, self.pulse_proc_progress)
     self.stdout_updater = Tailer(
         self.textview, self.stdout.name, pollable=proc)
     self.stdout_updater.start()
Example #7
0
 def connect(self):
     """Connect to the selected log file tailer."""
     try:
         cmd_tmpl = self.cmd_tmpls[self.filename]
     except (KeyError, TypeError):
         cmd_tmpl = None
     self.t = Tailer(self.logview, self.filename, cmd_tmpl=cmd_tmpl)
     self.t.start()
Example #8
0
 def update_view(self):
     self.t.stop()
     logbuffer = self.logview.get_buffer()
     s, e = logbuffer.get_bounds()
     self.reset_logbuffer()
     logbuffer.delete(s, e)
     self.log_label.set_text(self.path())
     self.t = Tailer(self.logview, self.path(), filters=[f for f in [self.task_filter, self.custom_filter] if f])
     self.t.start()
Example #9
0
 def connect(self):
     """Run the tailer command."""
     cmd = self.cmd_tmpl % {'rotation': self.rotation,
                            'suite_name': self.suite_name,
                            'suite_log': self.suite_log}
     self.t = Tailer(
         self.logview, cmd,
         filters=[f for f in [self.task_filter, self.custom_filter] if f])
     self.t.start()
Example #10
0
 def connect(self):
     """Connect to the selected log file tailer."""
     cmd = self.cmd_tmpl % {'subnum': self.nsubmit,
                            'suite_name': self.suite_name,
                            'task_id': self.task_id,
                            'job_log': self.choice}
     self.log_label.set_text(self.choice)
     self.t = Tailer(self.logview, cmd)
     self.t.start()
Example #11
0
 def run(self):
     proc = Popen(
         self.command, stdin=open(os.devnull), stdout=self.stdoutfile,
         stderr=STDOUT, shell=True)
     self.proc = proc
     gobject.timeout_add(40, self.pulse_proc_progress)
     tail_cmd_tmpl = glbl_cfg().get_host_item("tail command template")
     tail_cmd = tail_cmd_tmpl % {'filename': self.stdoutfile.name}
     self.stdout_updater = Tailer(self.textview, tail_cmd, pollable=proc)
     self.stdout_updater.start()
Example #12
0
 def run(self):
     proc = None
     if not self.ignore_command:
         proc = subprocess.Popen(
             self.command, stdout=self.stdout, stderr=subprocess.STDOUT,
             shell=True)
         self.proc = proc
         gobject.timeout_add(40, self.pulse_proc_progress)
     self.stdout_updater = Tailer(
         self.textview, self.stdout.name, pollable=proc)
     self.stdout_updater.start()
Example #13
0
class cylc_logviewer(logviewer):

    def __init__(self, name, dirname, task_list):
        self.task_list = task_list
        self.main_log = name
        self.dirname = dirname
        self.level = 0
        self.task_filter = None
        self.custom_filter = None

        logviewer.__init__(self, name, dirname, name)

    def create_gui_panel(self):
        logviewer.create_gui_panel(self)

        self.window = gtk.Window()
        # self.window.set_border_width(5)
        self.window.set_title("log viewer")
        self.window.set_size_request(800, 400)
        self.window.set_icon(get_icon())

        combobox = gtk.combo_box_new_text()
        combobox.append_text('Task')
        combobox.append_text('all')
        for task in self.task_list:
            combobox.append_text(task)

        combobox.connect("changed", self.filter_log)
        combobox.set_active(0)

        newer = gtk.Button("_newer")
        newer.connect("clicked", self.rotate_log, False)
        self.hbox.pack_end(newer, False)

        older = gtk.Button("_older")
        older.connect("clicked", self.rotate_log, True)
        self.hbox.pack_end(older, False)

        self.hbox.pack_end(combobox, False)

        filterbox = gtk.HBox()
        entry = gtk.Entry()
        entry.connect("activate", self.custom_filter_log)
        label = gtk.Label('Filter')
        filterbox.pack_start(label, True)
        filterbox.pack_start(entry, True)
        self.hbox.pack_end(filterbox, False)

        close = gtk.Button("_Close")
        close.connect("clicked", self.shutdown, None, self.window)
        self.hbox.pack_start(close, False)

        self.window.add(self.vbox)
        self.window.connect("delete_event", self.shutdown, self.window)

        self.window.show_all()

    def shutdown(self, w, e, wind):
        self.quit()
        wind.destroy()

    def filter_log(self, cb):
        model = cb.get_model()
        index = cb.get_active()
        if index == 0:
            return False

        task = model[index][0]
        if task == 'all':
            filter = None
        else:
            filter = '\\[' + task + '%\d+\\]'

        self.task_filter = filter
        self.update_view()

        # TODO - CHECK ALL BOOLEAN RETURN VALUES THROUGHOUT THE GUI
        return False

    def custom_filter_log(self, e):
        txt = e.get_text()
        if txt == '':
            filter = None
        else:
            filter = txt

        self.custom_filter = filter
        self.update_view()

        return False

    def current_log(self):
        try:
            return get_logs(self.dirname, self.main_log, False)[self.level]
        except IndexError:
            return None

    def rotate_log(self, bt, go_older):
        if go_older:
            self.level += 1
        else:
            self.level -= 1
        if self.level < 0:
            warning_dialog("""
At newest rotation; reloading in case
the suite has been restarted.""", self.window).warn()
            self.level = 0
            # but update view in case user started suite after gui
        if self.current_log() not in os.listdir(self.dirname):
            if go_older:
                warning_dialog("Older log not available", self.window).warn()
                self.level -= 1
                return
            else:
                warning_dialog("Newer log not available", self.window).warn()
                self.level += 1
                return
        else:
            self.filename = self.current_log()
        self.update_view()

    def update_view(self):
        self.t.stop()
        logbuffer = self.logview.get_buffer()
        s, e = logbuffer.get_bounds()
        self.reset_logbuffer()
        logbuffer.delete(s, e)
        self.log_label.set_text(self.path())
        self.t = Tailer(
            self.logview, self.path(),
            filters=[f for f in [self.task_filter, self.custom_filter] if f])
        self.t.start()
Example #14
0
class gcapture(object):
    """
Run a command as a subprocess and capture its stdout and stderr in real
time, to display in a GUI window. Examples:
    $ capture "echo foo"
    $ capture "echo hello && sleep 5 && echo bye"
Lines containing:
  'CRITICAL', 'WARNING', 'ERROR'
are displayed in red.
    $ capture "echo foo && echox bar"
    """
    def __init__(self,
                 command,
                 stdoutfile,
                 width=400,
                 height=400,
                 standalone=False,
                 ignore_command=False,
                 title=None):
        self.standalone = standalone
        self.command = command
        self.ignore_command = ignore_command
        self.stdout = stdoutfile
        self.stdout_updater = None
        self.proc = None
        self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
        self.window.set_border_width(5)
        if title is None:
            self.window.set_title('Command Output')
        else:
            self.window.set_title(title)
        self.window.connect("delete_event", self.quit)
        self.window.set_default_size(width, height)
        self.window.set_icon(get_icon())
        self.quit_already = False

        self.find_current = None
        self.find_current_iter = None
        self.search_warning_done = False

        sw = gtk.ScrolledWindow()
        sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
        sw.show()

        self.textview = gtk.TextView()
        self.textview.set_editable(False)
        self.textview.set_wrap_mode(gtk.WRAP_WORD)
        # Use a monospace font. This is safe - by testing - setting an
        # illegal font description has no effect.
        self.textview.modify_font(pango.FontDescription("monospace"))
        tb = self.textview.get_buffer()
        self.textview.show()

        self.ftag = tb.create_tag(None, background="#70FFA9")

        vbox = gtk.VBox()
        vbox.show()

        if not self.ignore_command:
            self.progress_bar = gtk.ProgressBar()
            self.progress_bar.set_text(command)
            self.progress_bar.set_pulse_step(0.04)
            self.progress_bar.show()
            vbox.pack_start(self.progress_bar, expand=False)
        self.command_label = gtk.Label(self.command)
        if self.ignore_command:
            self.command_label.show()
        vbox.pack_start(self.command_label, expand=False)

        sw.add(self.textview)

        frame = gtk.Frame()
        frame.add(sw)
        frame.show()
        vbox.add(frame)

        save_button = gtk.Button("Save As")
        save_button.connect("clicked", self.save, self.textview)
        save_button.show()

        hbox = gtk.HBox()
        hbox.pack_start(save_button, False)
        hbox.show()

        output_label = gtk.Label('output : ' + stdoutfile.name)
        output_label.show()
        hbox.pack_start(output_label, expand=True)

        self.freeze_button = gtk.ToggleButton("_Disconnect")
        self.freeze_button.set_active(False)
        self.freeze_button.connect("toggled", self.freeze)
        self.freeze_button.show()

        searchbox = gtk.HBox()
        searchbox.show()
        entry = gtk.Entry()
        entry.show()
        entry.connect("activate", self.enter_clicked)
        searchbox.pack_start(entry, True)
        b = gtk.Button("Find Next")
        b.connect_object('clicked', self.on_find_clicked, entry)
        b.show()
        searchbox.pack_start(b, False)
        searchbox.pack_start(self.freeze_button, False)

        close_button = gtk.Button("_Close")
        close_button.connect("clicked", self.quit, None, None)
        close_button.show()

        hbox.pack_end(close_button, False)

        vbox.pack_start(searchbox, False)
        vbox.pack_start(hbox, False)

        self.window.add(vbox)
        close_button.grab_focus()
        self.window.show()

    def run(self):
        proc = None
        if not self.ignore_command:
            proc = Popen(self.command,
                         stdin=open(os.devnull),
                         stdout=self.stdout,
                         stderr=STDOUT,
                         shell=True)
            self.proc = proc
            gobject.timeout_add(40, self.pulse_proc_progress)
        self.stdout_updater = Tailer(self.textview,
                                     self.stdout.name,
                                     pollable=proc)
        self.stdout_updater.start()

    def pulse_proc_progress(self):
        """While the process is running, pulse the progress bar a bit."""
        self.progress_bar.pulse()
        self.proc.poll()
        if self.proc.returncode is None and not self.stdout_updater.freeze:
            # Continue gobject.timeout_add loop.
            return True
        self.progress_bar.set_fraction(1.0)
        gobject.idle_add(self._handle_proc_completed)
        # Break gobject.timeout_add loop.
        return False

    def freeze(self, b):
        if b.get_active():
            self.stdout_updater.freeze = True
            b.set_label('_Reconnect')
        else:
            self.stdout_updater.freeze = False
            b.set_label('_Disconnect')

    def save(self, w, tv):
        tb = tv.get_buffer()

        start = tb.get_start_iter()
        end = tb.get_end_iter()
        txt = tb.get_text(start, end)

        dialog = gtk.FileChooserDialog(
            title='Save As',
            action=gtk.FILE_CHOOSER_ACTION_SAVE,
            buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_SAVE,
                     gtk.RESPONSE_OK))
        filter_ = gtk.FileFilter()
        filter_.set_name("any")
        filter_.add_pattern("*")
        dialog.add_filter(filter_)

        response = dialog.run()

        if response != gtk.RESPONSE_OK:
            dialog.destroy()
            return False

        fname = dialog.get_filename()
        dialog.destroy()

        try:
            f = open(fname, 'wb')
        except IOError, x:
            warning_dialog(str(x), self.window).warn()
        else:
Example #15
0
class cylc_logviewer(logviewer):
    def __init__(self, name, dirname, task_list):
        self.task_list = task_list
        self.main_log = name
        self.dirname = dirname
        self.level = 0
        self.task_filter = None
        self.custom_filter = None

        logviewer.__init__(self, name, dirname, name)

    def create_gui_panel(self):
        logviewer.create_gui_panel(self)

        self.window = gtk.Window()
        # self.window.set_border_width(5)
        self.window.set_title("log viewer")
        self.window.set_size_request(800, 400)
        self.window.set_icon(get_icon())

        combobox = gtk.combo_box_new_text()
        combobox.append_text('Task')
        combobox.append_text('all')
        for task in self.task_list:
            combobox.append_text(task)

        combobox.connect("changed", self.filter_log)
        combobox.set_active(0)

        newer = gtk.Button("_newer")
        newer.connect("clicked", self.rotate_log, False)
        self.hbox.pack_end(newer, False)

        older = gtk.Button("_older")
        older.connect("clicked", self.rotate_log, True)
        self.hbox.pack_end(older, False)

        self.hbox.pack_end(combobox, False)

        filterbox = gtk.HBox()
        entry = gtk.Entry()
        entry.connect("activate", self.custom_filter_log)
        label = gtk.Label('Filter')
        filterbox.pack_start(label, True)
        filterbox.pack_start(entry, True)
        self.hbox.pack_end(filterbox, False)

        close = gtk.Button("_Close")
        close.connect("clicked", self.shutdown, None, self.window)
        self.hbox.pack_start(close, False)

        self.window.add(self.vbox)
        self.window.connect("delete_event", self.shutdown, self.window)

        self.window.show_all()

    def shutdown(self, w, e, wind):
        self.quit()
        wind.destroy()

    def filter_log(self, cb):
        model = cb.get_model()
        index = cb.get_active()
        if index == 0:
            return False

        task = model[index][0]
        if task == 'all':
            filter_ = None
        else:
            filter_ = '\\[' + task + '%\d+\\]'

        self.task_filter = filter_
        self.update_view()

        # TODO - CHECK ALL BOOLEAN RETURN VALUES THROUGHOUT THE GUI
        return False

    def custom_filter_log(self, e):
        txt = e.get_text()
        if txt == '':
            filter_ = None
        else:
            filter_ = txt

        self.custom_filter = filter_
        self.update_view()

        return False

    def current_log(self):
        try:
            return get_logs(self.dirname, self.main_log, False)[self.level]
        except IndexError:
            return None

    def rotate_log(self, bt, go_older):
        if go_older:
            self.level += 1
        else:
            self.level -= 1
        if self.level < 0:
            warning_dialog(
                """
At newest rotation; reloading in case
the suite has been restarted.""", self.window).warn()
            self.level = 0
            # but update view in case user started suite after gui
        if self.current_log() not in os.listdir(self.dirname):
            if go_older:
                warning_dialog("Older log not available", self.window).warn()
                self.level -= 1
                return
            else:
                warning_dialog("Newer log not available", self.window).warn()
                self.level += 1
                return
        else:
            self.filename = self.current_log()
        self.update_view()

    def update_view(self):
        self.t.stop()
        logbuffer = self.logview.get_buffer()
        s, e = logbuffer.get_bounds()
        self.reset_logbuffer()
        logbuffer.delete(s, e)
        self.log_label.set_text(self.path())
        self.t = Tailer(
            self.logview,
            self.path(),
            filters=[f for f in [self.task_filter, self.custom_filter] if f])
        self.t.start()
Example #16
0
class SuiteLogViewer(logviewer):
    """A popup window to view suite logs.

    Implemented using "cylc cat-log".

    """

    LABEL_ALL_LINES = "(all lines)"
    LABEL_ALL_TASKS = "(all tasks)"

    def __init__(self, suite_name, suite_log, remote_run_opts, task_list=None):
        """Initialise the suite log viewer."""
        if task_list is None:
            self.task_list = []
        else:
            self.task_list = task_list
        self.suite_name = suite_name
        self.suite_log = suite_log
        self.rotation = 0
        self.cmd_tmpl = "cylc cat-log %s" % remote_run_opts + (
            " -m t -r %(rotation)s -f %(suite_log)s %(suite_name)s")
        self.task_filter = None
        self.custom_filter = None
        logviewer.__init__(self)

    def create_gui_panel(self):
        """Create the GUI panel."""
        logviewer.create_gui_panel(self)

        self.window = gtk.Window()
        # self.window.set_border_width(5)
        self.window.set_title("log viewer")
        self.window.set_size_request(800, 400)
        self.window.set_icon(get_icon())

        combobox = gtk.combo_box_new_text()
        combobox.append_text(self.LABEL_ALL_LINES)
        combobox.append_text(self.LABEL_ALL_TASKS)
        for task in self.task_list:
            combobox.append_text(task)

        combobox.connect("changed", self.filter_log)
        combobox.set_active(0)

        newer = gtk.Button("_newer")
        newer.connect("clicked", self.rotate_log, False)
        self.hbox.pack_end(newer, False)

        older = gtk.Button("_older")
        older.connect("clicked", self.rotate_log, True)
        self.hbox.pack_end(older, False)

        self.hbox.pack_end(combobox, False)

        filterbox = gtk.HBox()
        entry = gtk.Entry()
        entry.connect("activate", self.custom_filter_log)
        label = gtk.Label('Filter')
        filterbox.pack_start(label, True)
        filterbox.pack_start(entry, True)
        self.hbox.pack_end(filterbox, False)

        close = gtk.Button("_Close")
        close.connect("clicked", self.shutdown, None, self.window)
        self.hbox.pack_start(close, False)

        self.window.add(self.vbox)
        self.window.connect("delete_event", self.shutdown, self.window)

        self.window.show_all()

    def shutdown(self, w, e, wind):
        """Quite the suite log viewer."""
        self.quit()
        wind.destroy()

    def filter_log(self, cb):
        """Filter for task names."""
        model = cb.get_model()
        index = cb.get_active()
        task = model[index][0]
        # Good enough to match "[task.CYCLE]"?
        if task == self.LABEL_ALL_LINES:
            filter_ = None
        elif task == self.LABEL_ALL_TASKS:
            filter_ = r'\[' + TaskID.ID_RE + r'\]'
        else:
            filter_ = r'\[' + task + TaskID.DELIM_RE + TaskID.POINT_RE + r'\]'
        self.task_filter = filter_
        self.update_view()
        return False

    def custom_filter_log(self, e):
        """Filter for arbitrary text."""
        txt = e.get_text()
        if txt == '':
            filter_ = None
        else:
            filter_ = txt
        self.custom_filter = filter_
        self.update_view()
        return False

    def rotate_log(self, bt, go_older):
        """Switch to other log rotations."""
        if go_older:
            self.rotation += 1
        elif self.rotation > 0:
            self.rotation -= 1
        self.update_view()

    def connect(self):
        """Run the tailer command."""
        cmd = self.cmd_tmpl % {
            'rotation': self.rotation,
            'suite_name': self.suite_name,
            'suite_log': self.suite_log
        }
        self.t = Tailer(
            self.logview,
            cmd,
            filters=[f for f in [self.task_filter, self.custom_filter] if f])
        self.t.start()

    def update_view(self):
        """Restart the log view on another log."""
        if self.t is None:
            return False
        self.t.stop()
        logbuffer = self.logview.get_buffer()
        s, e = logbuffer.get_bounds()
        self.reset_logbuffer()
        logbuffer.delete(s, e)
        label = "log (rot %d)" % self.rotation
        self.log_label.set_text(label)
        self.connect()
Example #17
0
class ComboLogViewer(logviewer):
    """Implement a viewer for task jobs in the "cylc gui".

    It has a a combo box for log file selection.

    task_id -- The NAME.POINT of a task proxy.
    filenames -- The names of the task job logs.
    cmd_tmpls -- A dict to map file names and alternate commands to tail follow
                 the file.
    init_active_index -- The index for selecting the initial log file.
    """

    LABEL_TEXT = "Choose Log File: "

    def __init__(self, task_id, filenames, cmd_tmpls, init_active_index):
        self.filenames = OrderedDict()
        name_str, point_str = TaskID.split(task_id)
        for filename in filenames:
            try:
                f_point_str, f_name_str, f_submit_num_str, f_base_name = (
                    filename.rsplit(os.sep, 4)[1:])
                if (f_point_str == point_str and f_name_str == name_str
                        and int(f_submit_num_str) and f_base_name):
                    name = f_submit_num_str + os.sep + f_base_name
                if ":" in filename:
                    name += " (%s)" % (filename.split(":", 1)[0])
            except ValueError:
                name = filename
            self.filenames[name] = filename
        self.init_active_index = init_active_index
        self.cmd_tmpls = cmd_tmpls
        logviewer.__init__(self, task_id, None,
                           filenames[self.init_active_index])

    def connect(self):
        """Connect to the selected log file tailer."""
        try:
            cmd_tmpl = self.cmd_tmpls[self.filename]
        except (KeyError, TypeError):
            cmd_tmpl = None
        self.t = Tailer(self.logview, self.filename, cmd_tmpl=cmd_tmpl)
        self.t.start()

    def create_gui_panel(self):
        """Create the panel."""
        logviewer.create_gui_panel(self)
        label = gtk.Label(self.LABEL_TEXT)
        combobox = gtk.combo_box_new_text()

        for name in self.filenames:
            combobox.append_text(name)

        combobox.connect("changed", self.switch_log)
        if self.init_active_index:
            combobox.set_active(self.init_active_index)
        else:
            combobox.set_active(0)

        self.hbox.pack_end(combobox, False)
        self.hbox.pack_end(label, False)

    def switch_log(self, callback):
        """Switch to another file, if necessary."""
        if self.t is None:
            return False
        model = callback.get_model()
        index = callback.get_active()

        name = model[index][0]
        filename = self.filenames[name]
        if filename != self.filename:
            self.filename = filename
            self.t.stop()
            self.t.join()
            logbuffer = self.logview.get_buffer()
            pos_start, pos_end = logbuffer.get_bounds()
            self.reset_logbuffer()
            logbuffer.delete(pos_start, pos_end)
            self.log_label.set_text(name)
            self.connect()

        return False
Example #18
0
class gcapture(object):
    """
Run a command as a subprocess and capture its stdout and stderr in real
time, to display in a GUI window. Examples:
    $ capture "echo foo"
    $ capture "echo hello && sleep 5 && echo bye"
Lines containing:
  'CRITICAL', 'WARNING', 'ERROR'
are displayed in red.
    $ capture "echo foo && echox bar"
    """
    def __init__(self, command, stdoutfile, width=400, height=400,
                 standalone=False, ignore_command=False, title=None):
        self.standalone = standalone
        self.command = command
        self.ignore_command = ignore_command
        self.stdout = stdoutfile
        self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
        self.window.set_border_width(5)
        if title is None:
            self.window.set_title('Command Output')
        else:
            self.window.set_title(title)
        self.window.connect("delete_event", self.quit)
        self.window.set_default_size(width, height)
        self.window.set_icon(get_icon())
        self.quit_already = False

        self.find_current = None
        self.find_current_iter = None
        self.search_warning_done = False

        sw = gtk.ScrolledWindow()
        sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
        sw.show()

        self.textview = gtk.TextView()
        self.textview.set_editable(False)
        self.textview.set_wrap_mode(gtk.WRAP_WORD)
        # Use a monospace font. This is safe - by testing - setting an
        # illegal font description has no effect.
        self.textview.modify_font(pango.FontDescription("monospace"))
        tb = self.textview.get_buffer()
        self.textview.show()

        self.ftag = tb.create_tag(None, background="#70FFA9")

        vbox = gtk.VBox()
        vbox.show()

        if not self.ignore_command:
            self.progress_bar = gtk.ProgressBar()
            self.progress_bar.set_text(command)
            self.progress_bar.set_pulse_step(0.04)
            self.progress_bar.show()
            vbox.pack_start(self.progress_bar, expand=False)
        self.command_label = gtk.Label(self.command)
        if self.ignore_command:
            self.command_label.show()
        vbox.pack_start(self.command_label, expand=False)

        sw.add(self.textview)

        frame = gtk.Frame()
        frame.add(sw)
        frame.show()
        vbox.add(frame)

        save_button = gtk.Button("Save As")
        save_button.connect("clicked", self.save, self.textview)
        save_button.show()

        hbox = gtk.HBox()
        hbox.pack_start(save_button, False)
        hbox.show()

        output_label = gtk.Label('output : ' + stdoutfile.name)
        output_label.show()
        hbox.pack_start(output_label, expand=True)

        self.freeze_button = gtk.ToggleButton("_Disconnect")
        self.freeze_button.set_active(False)
        self.freeze_button.connect("toggled", self.freeze)
        self.freeze_button.show()

        searchbox = gtk.HBox()
        searchbox.show()
        entry = gtk.Entry()
        entry.show()
        entry.connect("activate", self.enter_clicked)
        searchbox.pack_start(entry, True)
        b = gtk.Button("Find Next")
        b.connect_object('clicked', self.on_find_clicked, entry)
        b.show()
        searchbox.pack_start(b, False)
        searchbox.pack_start(self.freeze_button, False)

        close_button = gtk.Button("_Close")
        close_button.connect("clicked", self.quit, None, None)
        close_button.show()

        hbox.pack_end(close_button, False)

        vbox.pack_start(searchbox, False)
        vbox.pack_start(hbox, False)

        self.window.add(vbox)
        close_button.grab_focus()
        self.window.show()

    def run(self):
        proc = None
        if not self.ignore_command:
            proc = subprocess.Popen(
                self.command, stdout=self.stdout, stderr=subprocess.STDOUT,
                shell=True)
            self.proc = proc
            gobject.timeout_add(40, self.pulse_proc_progress)
        self.stdout_updater = Tailer(
            self.textview, self.stdout.name, pollable=proc)
        self.stdout_updater.start()

    def pulse_proc_progress(self):
        """While the process is running, pulse the progress bar a bit."""
        self.progress_bar.pulse()
        self.proc.poll()
        if self.proc.returncode is None and not self.stdout_updater.freeze:
            # Continue gobject.timeout_add loop.
            return True
        self.progress_bar.set_fraction(1.0)
        gobject.idle_add(self._handle_proc_completed)
        # Break gobject.timeout_add loop.
        return False

    def freeze(self, b):
        if b.get_active():
            self.stdout_updater.freeze = True
            b.set_label('_Reconnect')
        else:
            self.stdout_updater.freeze = False
            b.set_label('_Disconnect')

    def save(self, w, tv):
        tb = tv.get_buffer()

        start = tb.get_start_iter()
        end = tb.get_end_iter()
        txt = tb.get_text(start, end)

        dialog = gtk.FileChooserDialog(
            title='Save As',
            action=gtk.FILE_CHOOSER_ACTION_SAVE,
            buttons=(
                gtk.STOCK_CANCEL,
                gtk.RESPONSE_CANCEL,
                gtk.STOCK_SAVE,
                gtk.RESPONSE_OK))
        filter = gtk.FileFilter()
        filter.set_name("any")
        filter.add_pattern("*")
        dialog.add_filter(filter)

        response = dialog.run()

        if response != gtk.RESPONSE_OK:
            dialog.destroy()
            return False

        fname = dialog.get_filename()
        dialog.destroy()

        try:
            f = open(fname, 'wb')
        except IOError, x:
            warning_dialog(str(x), self.window).warn()
        else:
Example #19
0
class logviewer(object):
    def __init__(self, name, dirname, filename):
        self.name = name
        self.dirname = dirname
        self.filename = filename
        self.t = None

        self.find_current = None
        self.find_current_iter = None
        self.search_warning_done = False

        self.create_gui_panel()
        self.logview.get_buffer()

        self.connect()

    def clear_and_reconnect(self):
        self.t.stop()
        self.clear()
        self.connect()

    def clear(self):
        logbuffer = self.logview.get_buffer()
        s, e = logbuffer.get_bounds()
        logbuffer.delete(s, e)

    def path(self):
        if self.dirname and not os.path.isabs(self.filename):
            return os.path.join(self.dirname, self.filename)
        else:
            return self.filename

    def connect(self):
        self.t = Tailer(self.logview, self.path())
        self.t.start()

    def quit_w_e(self, w, e):
        self.t.stop()

    def quit(self):
        self.t.stop()

    def get_widget(self):
        return self.vbox

    def reset_logbuffer(self):
        # clear log buffer iters and tags
        logbuffer = self.logview.get_buffer()
        s, e = logbuffer.get_bounds()
        logbuffer.remove_all_tags(s, e)
        self.find_current_iter = None
        self.find_current = None

    def enter_clicked(self, e, tv):
        self.on_find_clicked(tv, e)

    def on_find_clicked(self, tv, e):
        needle = e.get_text()
        if not needle:
            return

        self.t.freeze = True
        self.freeze_button.set_active(True)
        self.freeze_button.set_label('Reconnect')
        if not self.search_warning_done:
            warning_dialog(
                "Find Next disconnects the live feed;" +
                " click Reconnect when you're done").warn()
            self.search_warning_done = True

        tb = tv.get_buffer()

        if needle == self.find_current:
            s = self.find_current_iter
        else:
            s, e = tb.get_bounds()
            tb.remove_all_tags(s, e)
            s = tb.get_end_iter()
            tv.scroll_to_iter(s, 0)
        try:
            f, l = s.backward_search(needle, gtk.TEXT_SEARCH_TEXT_ONLY)
        except:
            warning_dialog('"' + needle + '"' + " not found").warn()
        else:
            tag = tb.create_tag(None, background="#70FFA9")
            tb.apply_tag(tag, f, l)
            self.find_current_iter = f
            self.find_current = needle
            tv.scroll_to_iter(f, 0)

    def freeze_log(self, b):
        # TODO - HANDLE MORE STUFF IN THREADS LIKE THIS, RATHER THAN
        # PASSING IN ARGUMENTS?
        if b.get_active():
            self.t.freeze = True
            b.set_label('Re_connect')
            self.reset_logbuffer()
        else:
            self.t.freeze = False
            b.set_label('Dis_connect')

        return False

    def create_gui_panel(self):
        self.logview = gtk.TextView()
        self.logview.set_editable(False)
        # Use a monospace font. This is safe - by testing - setting an
        # illegal font description has no effect.
        self.logview.modify_font(pango.FontDescription("monospace"))

        searchbox = gtk.HBox()
        entry = gtk.Entry()
        entry.connect("activate", self.enter_clicked, self.logview)
        searchbox.pack_start(entry, True)
        b = gtk.Button("Find Next")
        b.connect_object('clicked', self.on_find_clicked, self.logview, entry)
        searchbox.pack_start(b, False)

        self.hbox = gtk.HBox()

        self.freeze_button = gtk.ToggleButton("Dis_connect")
        self.freeze_button.set_active(False)
        self.freeze_button.connect("toggled", self.freeze_log)

        searchbox.pack_end(self.freeze_button, False)

        sw = gtk.ScrolledWindow()
        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        sw.add(self.logview)
        self.logview.set_border_width(5)
        self.logview.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse("#fff"))

        self.vbox = gtk.VBox()

        self.log_label = gtk.Label(self.path())
        self.log_label.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse("#00a"))
        self.vbox.pack_start(self.log_label, False)

        self.vbox.pack_start(sw, True)
        self.vbox.pack_start(searchbox, False)
        self.vbox.pack_start(self.hbox, False)
Example #20
0
class ComboLogViewer(logviewer):
    """Implement a viewer for task job logs in the GUI, via "cylc cat-log".

    It has a a combo box for log file selection.

    """
    LABEL_TEXT = "File: "
    LABEL_TEXT2 = "Submit: "

    def __init__(self, suite, task_id, choice, extra_logs, nsubmits,
                 remote_run_opts):
        self.suite_name = suite
        self.task_id = task_id
        self.nsubmits = nsubmits
        self.nsubmit = nsubmits
        self.extra_logs = extra_logs
        self.suite = suite
        self.choice = choice
        self.cmd_tmpl = "cylc cat-log %s" % remote_run_opts + (
            " -m t -s %(subnum)s -f %(job_log)s %(suite_name)s %(task_id)s")
        logviewer.__init__(self)

    def connect(self):
        """Connect to the selected log file tailer."""
        cmd = self.cmd_tmpl % {
            'subnum': self.nsubmit,
            'suite_name': self.suite_name,
            'task_id': self.task_id,
            'job_log': self.choice
        }
        self.log_label.set_text(self.choice)
        self.t = Tailer(self.logview, cmd)
        self.t.start()

    def create_gui_panel(self):
        """Create the panel."""
        logviewer.create_gui_panel(self)

        label2 = gtk.Label(self.LABEL_TEXT2)
        combobox2 = gtk.combo_box_new_text()
        snums = range(1, self.nsubmits + 1)
        for snum in snums:
            combobox2.append_text(str(snum))
        combobox2.connect("changed", self.switch_snum)
        if self.nsubmit in snums:
            combobox2.set_active(snums.index(self.nsubmit))
        self.hbox.pack_end(combobox2, False)
        self.hbox.pack_end(label2, False)

        label = gtk.Label(self.LABEL_TEXT)
        combobox = gtk.combo_box_new_text()
        names = JOB_LOG_OPTS.values() + self.extra_logs
        for name in names:
            combobox.append_text(name)
        combobox.connect("changed", self.switch_log)
        combobox.set_active(names.index(self.choice))
        self.hbox.pack_end(combobox, False)
        self.hbox.pack_end(label, False)

    def switch_log(self, callback):
        """Switch to another file."""
        if self.t is None:
            return False
        model = callback.get_model()
        index = callback.get_active()

        filename = model[index][0]
        if filename != self.choice:
            self.choice = filename
            self.t.stop()
            self.t.join()
            logbuffer = self.logview.get_buffer()
            pos_start, pos_end = logbuffer.get_bounds()
            self.reset_logbuffer()
            logbuffer.delete(pos_start, pos_end)
            self.connect()
        return False

    def switch_snum(self, callback):
        """Switch to another file."""
        if self.t is None:
            return False
        model = callback.get_model()
        index = callback.get_active()
        snum = model[index][0]
        if snum != self.nsubmit:
            self.nsubmit = snum
            self.t.stop()
            self.t.join()
            logbuffer = self.logview.get_buffer()
            pos_start, pos_end = logbuffer.get_bounds()
            self.reset_logbuffer()
            logbuffer.delete(pos_start, pos_end)
            self.connect()
        return False
Example #21
0
class ComboLogViewer(logviewer):

    """Implement a viewer for task jobs in the "cylc gui".

    It has a a combo box for log file selection.

    task_id -- The NAME.POINT of a task proxy.
    filenames -- The names of the task job logs.
    cmd_tmpls -- A dict to map file names and alternate commands to tail follow
                 the file.
    init_active_index -- The index for selecting the initial log file.
    """

    LABEL_TEXT = "Choose Log File: "

    def __init__(self, task_id, filenames, cmd_tmpls, init_active_index):
        self.filenames = OrderedDict()
        name_str, point_str = TaskID.split(task_id)
        for filename in filenames:
            try:
                f_point_str, f_name_str, f_submit_num_str, f_base_name = (
                    filename.rsplit(os.sep, 4)[1:])
                if (f_point_str == point_str and f_name_str == name_str and
                        int(f_submit_num_str) and f_base_name):
                    name = f_submit_num_str + os.sep + f_base_name
                if ":" in filename:
                    name += " (%s)" % (filename.split(":", 1)[0])
            except ValueError:
                name = filename
            self.filenames[name] = filename
        self.init_active_index = init_active_index
        self.cmd_tmpls = cmd_tmpls
        logviewer.__init__(
            self, task_id, None, filenames[self.init_active_index])

    def connect(self):
        """Connect to the selected log file tailer."""
        try:
            cmd_tmpl = self.cmd_tmpls[self.filename]
        except (KeyError, TypeError):
            cmd_tmpl = None
        self.t = Tailer(self.logview, self.filename, cmd_tmpl=cmd_tmpl)
        self.t.start()

    def create_gui_panel(self):
        """Create the panel."""
        logviewer.create_gui_panel(self)
        label = gtk.Label(self.LABEL_TEXT)
        combobox = gtk.combo_box_new_text()

        for name in self.filenames:
            combobox.append_text(name)

        combobox.connect("changed", self.switch_log)
        if self.init_active_index:
            combobox.set_active(self.init_active_index)
        else:
            combobox.set_active(0)

        self.hbox.pack_end(combobox, False)
        self.hbox.pack_end(label, False)

    def switch_log(self, callback):
        """Switch to another file, if necessary."""
        if self.t is None:
            return False
        model = callback.get_model()
        index = callback.get_active()

        name = model[index][0]
        filename = self.filenames[name]
        if filename != self.filename:
            self.filename = filename
            self.t.stop()
            self.t.join()
            logbuffer = self.logview.get_buffer()
            pos_start, pos_end = logbuffer.get_bounds()
            self.reset_logbuffer()
            logbuffer.delete(pos_start, pos_end)
            self.log_label.set_text(name)
            self.connect()

        return False
Example #22
0
class SuiteLogViewer(logviewer):
    """A popup window to view suite logs.

    Implemented using "cylc cat-log".

    """

    LABEL_ALL_LINES = "(all lines)"
    LABEL_ALL_TASKS = "(all tasks)"

    def __init__(self, suite_name, suite_log, remote_run_opts, task_list=None):
        """Initialise the suite log viewer."""
        if task_list is None:
            self.task_list = []
        else:
            self.task_list = task_list
        self.suite_name = suite_name
        self.suite_log = suite_log
        self.suite_log_name = SUITE_LOG_OPTS[suite_log]
        self.rotation = 0
        self.cmd_tmpl = "cylc cat-log %s" % remote_run_opts + (
            " -m t -r %(rotation)s -f %(suite_log)s %(suite_name)s")
        self.task_filter = None
        self.custom_filter = None
        logviewer.__init__(self)

    def create_gui_panel(self):
        """Create the GUI panel."""
        logviewer.create_gui_panel(self)

        self.window = gtk.Window()
        # self.window.set_border_width(5)
        self.window.set_title("log viewer")
        self.window.set_size_request(800, 400)
        self.window.set_icon(get_icon())

        combobox = gtk.combo_box_new_text()
        combobox.append_text(self.LABEL_ALL_LINES)
        combobox.append_text(self.LABEL_ALL_TASKS)
        for task in self.task_list:
            combobox.append_text(task)

        combobox.connect("changed", self.filter_log)
        combobox.set_active(0)

        newer = gtk.Button("_newer")
        newer.connect("clicked", self.rotate_log, False)
        self.hbox.pack_end(newer, False)

        older = gtk.Button("_older")
        older.connect("clicked", self.rotate_log, True)
        self.hbox.pack_end(older, False)

        self.hbox.pack_end(combobox, False)

        filterbox = gtk.HBox()
        entry = gtk.Entry()
        entry.connect("activate", self.custom_filter_log)
        label = gtk.Label('Filter')
        filterbox.pack_start(label, True)
        filterbox.pack_start(entry, True)
        self.hbox.pack_end(filterbox, False)

        close = gtk.Button("_Close")
        close.connect("clicked", self.shutdown, None, self.window)
        self.hbox.pack_start(close, False)

        self.window.add(self.vbox)
        self.window.connect("delete_event", self.shutdown, self.window)

        self.window.show_all()

    def shutdown(self, w, e, wind):
        """Quite the suite log viewer."""
        self.quit()
        wind.destroy()

    def filter_log(self, cb):
        """Filter for task names."""
        model = cb.get_model()
        index = cb.get_active()
        task = model[index][0]
        # Good enough to match "[task.CYCLE]"?
        if task == self.LABEL_ALL_LINES:
            filter_ = None
        elif task == self.LABEL_ALL_TASKS:
            filter_ = r'\[' + TaskID.ID_RE + r'\]'
        else:
            filter_ = r'\[' + task + TaskID.DELIM_RE + TaskID.POINT_RE + r'\]'
        self.task_filter = filter_
        self.update_view()
        return False

    def custom_filter_log(self, e):
        """Filter for arbitrary text."""
        txt = e.get_text()
        if txt == '':
            filter_ = None
        else:
            filter_ = txt
        self.custom_filter = filter_
        self.update_view()
        return False

    def rotate_log(self, bt, go_older):
        """Switch to other log rotations."""
        if go_older:
            self.rotation += 1
        elif self.rotation > 0:
            self.rotation -= 1
        self.update_view()

    def connect(self):
        """Run the tailer command."""
        cmd = self.cmd_tmpl % {'rotation': self.rotation,
                               'suite_name': self.suite_name,
                               'suite_log': self.suite_log}
        self.t = Tailer(
            self.logview, cmd,
            filters=[f for f in [self.task_filter, self.custom_filter] if f])
        self.t.start()

    def update_view(self):
        """Restart the log view on another log."""
        if self.t is None:
            return False
        self.t.stop()
        logbuffer = self.logview.get_buffer()
        s, e = logbuffer.get_bounds()
        self.reset_logbuffer()
        logbuffer.delete(s, e)
        label = "%s (rot %d)" % (self.suite_log_name, self.rotation)
        self.log_label.set_text(label)
        self.connect()
Example #23
0
class ComboLogViewer(logviewer):

    """Implement a viewer for task jobs in the "cylc gui".

    It has a a combo box for log file selection.

    task_id -- The NAME.POINT of a task proxy.
    filenames -- The names of the task job logs.
    cmd_tmpls -- A dict to map file names and alternate commands to tail follow
                 the file.
    init_active_index -- The index for selecting the initial log file.
    """

    LABEL_TEXT = "Choose Log File: "

    def __init__(self, task_id, filenames, cmd_tmpls, init_active_index):
        self.filenames = filenames
        self.init_active_index = init_active_index
        self.cmd_tmpls = cmd_tmpls
        self.common_dir = os.path.dirname(os.path.commonprefix(self.filenames))
        logviewer.__init__(
            self, task_id, None, self.filenames[self.init_active_index])

    def connect(self):
        """Connect to the selected log file tailer."""
        try:
            cmd_tmpl = self.cmd_tmpls[self.filename]
        except (KeyError, TypeError):
            cmd_tmpl = None
        self.t = Tailer(self.logview, self.filename, cmd_tmpl=cmd_tmpl)
        self.t.start()

    def create_gui_panel(self):
        """Create the panel."""
        logviewer.create_gui_panel(self)
        label = gtk.Label(self.LABEL_TEXT)
        combobox = gtk.combo_box_new_text()

        for filename in self.filenames:
            relpath = os.path.relpath(filename, self.common_dir)
            if len(relpath) < len(filename):
                combobox.append_text(relpath)
            else:
                combobox.append_text(filename)

        combobox.connect("changed", self.switch_log)
        if self.init_active_index:
            combobox.set_active(self.init_active_index)
        else:
            combobox.set_active(0)

        self.hbox.pack_end(combobox, False)
        self.hbox.pack_end(label, False)

    def switch_log(self, callback):
        """Switch to another file, if necessary."""
        if self.t is None:
            return False
        model = callback.get_model()
        index = callback.get_active()

        name = model[index][0]
        if name in self.filenames:
            filename = name
        else:
            filename = os.path.join(self.common_dir, name)
        if filename != self.filename:
            self.filename = filename
            self.t.stop()
            self.t.join()
            logbuffer = self.logview.get_buffer()
            pos_start, pos_end = logbuffer.get_bounds()
            self.reset_logbuffer()
            logbuffer.delete(pos_start, pos_end)
            self.log_label.set_text(name)
            self.connect()

        return False
Example #24
0
class ComboLogViewer(logviewer):

    """Implement a viewer for task job logs in the GUI, via "cylc cat-log".

    It has a a combo box for log file selection.

    """
    LABEL_TEXT = "File: "
    LABEL_TEXT2 = "Submit: "

    def __init__(self, suite, task_id, choice, extra_logs, nsubmits,
                 remote_run_opts):
        self.suite_name = suite
        self.task_id = task_id
        self.nsubmits = nsubmits
        self.nsubmit = nsubmits
        self.extra_logs = extra_logs
        self.suite = suite
        self.choice = choice
        self.cmd_tmpl = "cylc cat-log %s" % remote_run_opts + (
            " -m t -s %(subnum)s -f %(job_log)s %(suite_name)s %(task_id)s")
        logviewer.__init__(self)

    def connect(self):
        """Connect to the selected log file tailer."""
        cmd = self.cmd_tmpl % {'subnum': self.nsubmit,
                               'suite_name': self.suite_name,
                               'task_id': self.task_id,
                               'job_log': self.choice}
        self.log_label.set_text(self.choice)
        self.t = Tailer(self.logview, cmd)
        self.t.start()

    def create_gui_panel(self):
        """Create the panel."""
        logviewer.create_gui_panel(self)

        label2 = gtk.Label(self.LABEL_TEXT2)
        combobox2 = gtk.combo_box_new_text()
        snums = range(1, self.nsubmits + 1)
        for snum in snums:
            combobox2.append_text(str(snum))
        combobox2.connect("changed", self.switch_snum)
        combobox2.set_active(snums.index(self.nsubmit))
        self.hbox.pack_end(combobox2, False)
        self.hbox.pack_end(label2, False)

        label = gtk.Label(self.LABEL_TEXT)
        combobox = gtk.combo_box_new_text()
        names = JOB_LOG_OPTS.values() + self.extra_logs
        for name in names:
            combobox.append_text(name)
        combobox.connect("changed", self.switch_log)
        combobox.set_active(names.index(self.choice))
        self.hbox.pack_end(combobox, False)
        self.hbox.pack_end(label, False)

    def switch_log(self, callback):
        """Switch to another file."""
        if self.t is None:
            return False
        model = callback.get_model()
        index = callback.get_active()

        filename = model[index][0]
        if filename != self.choice:
            self.choice = filename
            self.t.stop()
            self.t.join()
            logbuffer = self.logview.get_buffer()
            pos_start, pos_end = logbuffer.get_bounds()
            self.reset_logbuffer()
            logbuffer.delete(pos_start, pos_end)
            self.connect()
        return False

    def switch_snum(self, callback):
        """Switch to another file."""
        if self.t is None:
            return False
        model = callback.get_model()
        index = callback.get_active()
        snum = model[index][0]
        if snum != self.nsubmit:
            self.nsubmit = snum
            self.t.stop()
            self.t.join()
            logbuffer = self.logview.get_buffer()
            pos_start, pos_end = logbuffer.get_bounds()
            self.reset_logbuffer()
            logbuffer.delete(pos_start, pos_end)
            self.connect()
        return False
Example #25
0
class logviewer(object):
    def __init__(self, name, dirname, filename):
        self.name = name
        self.dirname = dirname
        self.filename = filename
        self.t = None

        self.find_current = None
        self.find_current_iter = None
        self.search_warning_done = False

        self.freeze_button = None
        self.log_label = None
        self.logview = None
        self.hbox = None
        self.vbox = None
        self.create_gui_panel()
        self.logview.get_buffer()

        self.connect()

    def clear_and_reconnect(self):
        self.t.stop()
        self.clear()
        self.connect()

    def clear(self):
        logbuffer = self.logview.get_buffer()
        s, e = logbuffer.get_bounds()
        logbuffer.delete(s, e)

    def path(self):
        if self.dirname and not os.path.isabs(self.filename):
            return os.path.join(self.dirname, self.filename)
        else:
            return self.filename

    def connect(self):
        self.t = Tailer(self.logview, self.path())
        self.t.start()

    def quit_w_e(self, w, e):
        self.t.stop()

    def quit(self):
        self.t.stop()

    def get_widget(self):
        return self.vbox

    def reset_logbuffer(self):
        # clear log buffer iters and tags
        logbuffer = self.logview.get_buffer()
        s, e = logbuffer.get_bounds()
        logbuffer.remove_all_tags(s, e)
        self.find_current_iter = None
        self.find_current = None

    def enter_clicked(self, e, tv):
        self.on_find_clicked(tv, e)

    def on_find_clicked(self, tv, e):
        needle = e.get_text()
        if not needle:
            return

        self.t.freeze = True
        self.freeze_button.set_active(True)
        self.freeze_button.set_label('Reconnect')
        if not self.search_warning_done:
            warning_dialog("Find Next disconnects the live feed;" +
                           " click Reconnect when you're done").warn()
            self.search_warning_done = True

        tb = tv.get_buffer()

        if needle == self.find_current:
            s = self.find_current_iter
        else:
            s, e = tb.get_bounds()
            tb.remove_all_tags(s, e)
            s = tb.get_end_iter()
            tv.scroll_to_iter(s, 0)
        try:
            start, end = s.backward_search(needle, gtk.TEXT_SEARCH_TEXT_ONLY)
        except TypeError:
            # No search results.
            warning_dialog('"' + needle + '"' + " not found").warn()
        else:
            tag = tb.create_tag(None, background="#70FFA9")
            tb.apply_tag(tag, start, end)
            self.find_current_iter = start
            self.find_current = needle
            tv.scroll_to_iter(start, 0)

    def freeze_log(self, b):
        # TODO - HANDLE MORE STUFF IN THREADS LIKE THIS, RATHER THAN
        # PASSING IN ARGUMENTS?
        if b.get_active():
            self.t.freeze = True
            b.set_label('Re_connect')
            self.reset_logbuffer()
        else:
            self.t.freeze = False
            b.set_label('Dis_connect')

        return False

    def create_gui_panel(self):
        self.logview = gtk.TextView()
        self.logview.set_editable(False)
        # Use a monospace font. This is safe - by testing - setting an
        # illegal font description has no effect.
        self.logview.modify_font(pango.FontDescription("monospace"))

        searchbox = gtk.HBox()
        entry = gtk.Entry()
        entry.connect("activate", self.enter_clicked, self.logview)
        searchbox.pack_start(entry, True)
        b = gtk.Button("Find Next")
        b.connect_object('clicked', self.on_find_clicked, self.logview, entry)
        searchbox.pack_start(b, False)

        self.hbox = gtk.HBox()

        self.freeze_button = gtk.ToggleButton("Dis_connect")
        self.freeze_button.set_active(False)
        self.freeze_button.connect("toggled", self.freeze_log)

        searchbox.pack_end(self.freeze_button, False)

        sw = gtk.ScrolledWindow()
        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        sw.add(self.logview)
        self.logview.set_border_width(5)
        self.logview.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse("#fff"))

        self.vbox = gtk.VBox()

        self.log_label = gtk.Label(self.path())
        self.log_label.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse("#00a"))
        self.vbox.pack_start(self.log_label, False)

        self.vbox.pack_start(sw, True)
        self.vbox.pack_start(searchbox, False)
        self.vbox.pack_start(self.hbox, False)
Example #26
0
 def connect(self):
     self.t = Tailer(self.logview, self.path())
     self.t.start()
Example #27
0
 def connect(self):
     self.t = Tailer(self.logview, self.path())
     self.t.start()