class LogModel(QAbstractTableModel): COLUMNS = ['Log Level', 'Tag', 'PID', 'Log Line'] # TODO(dany): Use named tokens in the RegEx LINE_REGEX = re.compile(r'([VLEIWD])/(.*)\(\s*(\d+)\): (.*)') data_changed = Signal() def __init__(self, start_time): super(LogModel, self).__init__() self.start_time = start_time self.rows = [] self.pending = [] self.last_update = time.time() self.filename = None self.reader = None self.search_params = None def rowCount(self, parent=QModelIndex()): return len(self.rows) def columnCount(self, parent=QModelIndex()): return len(self.COLUMNS) def is_matching_row(self, row): string, is_cs, is_regex = self.search_params if is_regex: # TODO(dany): Maybe it would be faster to cache the regex object # and use it instead of having re compile it every time return re.match(string, row['Log Line'], re.I if is_cs else 0) else: if is_cs: return string.lower() in row['Log Line'].lower() else: return string in row['Log Line'] def data(self, index, role=Qt.DisplayRole): row = index.row() col = index.column() if role == Qt.DisplayRole: return self.rows[row][self.COLUMNS[col]] elif role == Qt.BackgroundColorRole: if self.search_params is None: return None if self.is_matching_row(self.rows[row]): return QColor(255, 255, 0) else: return None def headerData(self, index, orientation, role): if orientation == Qt.Horizontal and role == Qt.DisplayRole: return self.COLUMNS[index] else: return None def addItem(self, item): match = self.LINE_REGEX.match(item) if match is not None: log_level, tag, pid, line = match.groups() # TODO(dany): When the regex has tokens, I can just use groupdict self.pending.append({ 'Tag': tag.strip(), 'Log Level': log_level, 'PID': pid.strip(), 'Log Line': line }) if (time.time() - self.last_update) > 1: self.beginInsertRows(QModelIndex(), len(self.rows), len(self.rows) + len(self.pending) - 1) self.rows.extend(self.pending) self.endInsertRows() self.data_changed.emit() self.pending = [] self.last_update = time.time() def set_search_params(self, string, is_cs, is_re): if string != '': self.search_params = (string, is_cs, is_re) else: self.search_params = None self.dataChanged.emit(self.index(0, 0), self.index(self.rowCount(), self.columnCount())) def start(self): self.reader = LogcatReader(self, self.start_time) self.reader.start() def stop(self): if self.reader and self.reader.running.is_set(): self.reader.stop() self.reader.join() self.reader = None
def start(self): self.reader = LogcatReader(self, self.start_time) self.reader.start()