message_data_model.py
Go to the documentation of this file.
00001 # Software License Agreement (BSD License)
00002 #
00003 # Copyright (c) 2012, Willow Garage, Inc.
00004 # All rights reserved.
00005 #
00006 # Redistribution and use in source and binary forms, with or without
00007 # modification, are permitted provided that the following conditions
00008 # are met:
00009 #
00010 #  * Redistributions of source code must retain the above copyright
00011 #    notice, this list of conditions and the following disclaimer.
00012 #  * Redistributions in binary form must reproduce the above
00013 #    copyright notice, this list of conditions and the following
00014 #    disclaimer in the documentation and/or other materials provided
00015 #    with the distribution.
00016 #  * Neither the name of Willow Garage, Inc. nor the names of its
00017 #    contributors may be used to endorse or promote products derived
00018 #    from this software without specific prior written permission.
00019 #
00020 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00021 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00022 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00023 # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00024 # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00025 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00026 # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00027 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00028 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00029 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00030 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00031 # POSSIBILITY OF SUCH DAMAGE.
00032 
00033 from message_list import MessageList
00034 
00035 from python_qt_binding.QtCore import QAbstractTableModel, QDateTime, QModelIndex, Qt, qWarning
00036 from python_qt_binding.QtGui import QIcon
00037 
00038 
00039 class MessageDataModel(QAbstractTableModel):
00040     def __init__(self):
00041         super(MessageDataModel, self).__init__()
00042         self._messages = MessageList()
00043 
00044         self._time_format = 'hh:mm:ss.zzz (yyyy-MM-dd)'
00045         self._insert_message_queue = []
00046         self._paused = False
00047         self._message_limit = 20000
00048         self._error_icon = QIcon.fromTheme('dialog-error')
00049         self._warning_icon = QIcon.fromTheme('dialog-warning')
00050         self._info_icon = QIcon.fromTheme('dialog-information')
00051 
00052     # BEGIN Required implementations of QAbstractTableModel functions
00053 
00054     def rowCount(self, parent=None):
00055         return len(self._messages.get_message_list())
00056 
00057     def columnCount(self, parent=None):
00058         return self._messages.column_count()
00059 
00060     def data(self, index, role=None):
00061         if role is None:
00062             role = Qt.DisplayRole
00063         messagelist = self._messages.get_message_list()
00064         if index.row() >= 0 and index.row() < len(messagelist):
00065             if index.column() >= 0 and index.column() < messagelist[index.row()].count():
00066                 if role == Qt.DisplayRole:
00067                     elements = self._messages.message_members()
00068                     if elements[index.column()] == '_time':
00069                         return self.timedata_to_timestring(messagelist[index.row()].time_in_seconds())
00070                     else:
00071                         return getattr(messagelist[index.row()], elements[index.column()])
00072                 elif role == Qt.DecorationRole and index.column() == 0:
00073                     msgseverity = messagelist[index.row()].get_data(1)
00074                     if msgseverity in (self.tr('Debug'), self.tr('Info')):
00075                         return self._info_icon
00076                     elif msgseverity in (self.tr('Warn')):
00077                         return self._warning_icon
00078                     elif msgseverity in (self.tr('Error'), self.tr('Fatal')):
00079                         return self._error_icon
00080                 elif role == Qt.ToolTipRole:
00081                     return self.tr('Right click for menu.')
00082 
00083     def headerData(self, section, orientation, role=None):
00084         if role is None:
00085             role = Qt.DisplayRole
00086         if role == Qt.DisplayRole:
00087             if orientation == Qt.Horizontal:
00088                 sections = self._messages.message_members()
00089                 retval = sections[section][1:].capitalize()
00090                 return retval
00091             elif orientation == Qt.Vertical:
00092                 return '#%d' % (section + 1)
00093     # END Required implementations of QAbstractTableModel functions
00094 
00095     def timestring_to_timedata(self, timestring):
00096         """
00097         Converts a time string in the format of _time_format into a string
00098         of format '(unix timestamp).(fraction of second)'
00099         :param timestring: formatted time string ''str''
00100         :returns: seconds and fractions thereof ''str''
00101         """
00102         timeval = QDateTime.fromString(timestring, self._time_format).toTime_t()
00103         return str(timeval) + '.' + timestring[9:12]   # append '.(msecs)'
00104 
00105     def timedata_to_timestring(self, timedata):
00106         """
00107         Converts a string in the format of '(unix timestamp).(fraction of second)'
00108         into a string of format _time_format
00109         :param timedata:  seconds and fractions thereof ''str''
00110         :returns: formatted time string''str''
00111         """
00112         sec, fraction = timedata.split('.')
00113         if len(fraction) < 3:
00114             raise RuntimeError('Malformed timestring in timedata_to_timestring()')
00115         micro = int(fraction[:3])
00116         return QDateTime.fromTime_t(long(sec)).addMSecs(micro).toString(self._time_format)
00117 
00118     def insert_rows(self, msgs):
00119         """
00120         Wraps the insert_row function to minimize gui notification calls
00121         """
00122         if len(msgs) == 0:
00123             return
00124         self.beginInsertRows(QModelIndex(), len(self._messages.get_message_list()), len(self._messages.get_message_list()) + len(msgs) - 1)
00125         for msg in msgs:
00126             self.insert_row(msg, False)
00127         self.endInsertRows()
00128 
00129         if len(self.get_message_list()) > self._message_limit:
00130             self.beginRemoveRows(QModelIndex(), 0, len(self.get_message_list()) - self._message_limit - 1)
00131             del self.get_message_list()[0:len(self.get_message_list()) - self._message_limit]
00132             self.endRemoveRows()
00133 
00134     def insert_row(self, msg, notify_model=True):
00135         if notify_model:
00136             self.beginInsertRows(QModelIndex(), len(self._messages.get_message_list()), len(self._messages.get_message_list()))
00137         self._messages.add_message(msg)
00138         if notify_model:
00139             self.endInsertRows()
00140 
00141     def remove_rows(self, rowlist):
00142         """
00143         :param rowlist: list of row indexes, ''list(int)''
00144         :returns: True if the indexes were removed successfully, ''bool''
00145         OR
00146         :returns: False if there was an exception removing the rows, ''bool''
00147         """
00148         if len(rowlist) == 0:
00149             if len(self.get_message_list()) > 0:
00150                 try:
00151                     self.beginRemoveRows(QModelIndex(), 0, len(self.get_message_list()))
00152                     del self.get_message_list()[0:len(self.get_message_list())]
00153                     self.endRemoveRows()
00154                 except:
00155                     return False
00156         else:
00157             rowlist = list(set(rowlist))
00158             rowlist.sort(reverse=True)
00159             dellist = [rowlist[0]]
00160             for row in rowlist[1:]:
00161                 if dellist[-1] - 1 > row:
00162                     try:
00163                         self.beginRemoveRows(QModelIndex(), dellist[-1], dellist[0])
00164                         del self.get_message_list()[dellist[-1]:dellist[0] + 1]
00165                         self.endRemoveRows()
00166                     except:
00167                         return False
00168                     dellist = []
00169                 dellist.append(row)
00170             if len(dellist) > 0:
00171                 try:
00172                     self.beginRemoveRows(QModelIndex(), dellist[-1], dellist[0])
00173                     del self.get_message_list()[dellist[-1]:dellist[0] + 1]
00174                     self.endRemoveRows()
00175                 except:
00176                     return False
00177         return True
00178 
00179     def get_selected_text(self, rowlist):
00180         """
00181         Returns an easily readable block of text for the currently selected rows
00182         :param rowlist: list of row indexes, ''list(int)''
00183         :returns: the text from those indexes, ''str''
00184         """
00185         text = None
00186         if len(rowlist) != 0:
00187             text = ''
00188             rowlist = list(set(rowlist))
00189             for row in rowlist:
00190                 text += self.get_message_list()[row].pretty_print()
00191         return text
00192 
00193     def get_time_range(self, rowlist):
00194         """
00195         :param rowlist: a list of row indexes, ''list''
00196         :returns: a tuple of min and max times in a rowlist in '(unix timestamp).(fraction of second)' format, ''tuple(str,str)''
00197         """
00198         min_ = float("inf")
00199         max_ = float("-inf")
00200         for row in rowlist:
00201             item = self.get_message_list()[row].time_in_seconds()
00202             if float(item) > float(max_):
00203                 max_ = item
00204             if float(item) < float(min_):
00205                 min_ = item
00206         return min_, max_
00207 
00208     def get_unique_col_data(self, index, separate_topics=True):
00209         """
00210         :param index: column index, ''int''
00211         :param separate_topics: if true separates comma delimited strings into
00212         unique rows, ''bool''
00213         :returns: list of unique strings in the column, ''list[str]''
00214         """
00215         if index == 4 and separate_topics:
00216             unique_list = set()
00217             for topiclists in self._messages.get_unique_col_data(index):
00218                 for item in topiclists.split(','):
00219                     unique_list.add(item.strip())
00220             return list(unique_list)
00221         return self._messages.get_unique_col_data(index)
00222 
00223     def get_severity_list(self):
00224         return [self.tr('Debug'), self.tr('Info'), self.tr('Warn'), self.tr('Error'), self.tr('Fatal')]
00225 
00226     def get_data(self, row, col):
00227         return self._messages.get_data(row, col)
00228 
00229     def message_members(self):
00230         return self._messages.message_members()
00231 
00232     def load_from_file(self, filehandle):
00233         """
00234         Saves to an already open filehandle.
00235         :returns: True if loaded successfully, ''bool''
00236         OR
00237         :returns: False if load fails, ''bool''
00238         """
00239         line = filehandle.readline()
00240         lines = []
00241         if line == self._messages.header_print():
00242             while 1:
00243                 line = filehandle.readline()
00244                 if not line:
00245                     break
00246                 while line[-2] != "\"":
00247                     newline = filehandle.readline()
00248                     if not line:
00249                         qWarning('File does not appear to be a rqt_console message file: missing " at end of file')
00250                         return False
00251                     line = line + newline
00252                 lines.append(line)
00253             self.beginInsertRows(QModelIndex(), len(self._messages.get_message_list()), len(self._messages.get_message_list()) + len(lines) - 1)
00254             for line in lines:
00255                 try:
00256                     self._messages.append_from_text(line)
00257                 except ValueError:
00258                     qWarning('File does not appear to be a rqt_console message file: File line is malformed %s' % line)
00259             self.endInsertRows()
00260             self._paused = True
00261             return True
00262         else:
00263             qWarning('File does not appear to be a rqt_console message file: missing file header.')
00264             return False
00265 
00266     def get_message_list(self, start_time=None, end_time=None):
00267         """
00268         :param start_time: time to start in timestamp form (including decimal
00269         fractions of a second is acceptable, ''unixtimestamp'' (Optional)
00270         :param end_time: time to end in timestamp form (including decimal
00271         fractions of a second is acceptable, ''unixtimestamp'' (Optional)
00272         :returns: list of messages in the time range ''list[message]''
00273         """
00274         if start_time is not None:
00275             return self._messages.get_messages_in_time_range(start_time, end_time)
00276         else:
00277             return self._messages.get_message_list()


rqt_console
Author(s): Aaron Blasdel
autogenerated on Fri Jan 3 2014 11:54:30