Add new debug tools to FSComm to help on development. Check tools->debug.

This commit is contained in:
Joao Mesquita 2010-04-07 02:05:03 -03:00
parent d2ca27259a
commit ec8ab06c66
14 changed files with 1177 additions and 6 deletions

View File

@ -33,7 +33,10 @@ SOURCES += main.cpp \
preferences/prefaccounts.cpp \
account.cpp \
widgets/codecwidget.cpp \
channel.cpp
channel.cpp \
debugtools/consolewindow.cpp \
debugtools/sortfilterproxymodel.cpp \
debugtools/statedebugdialog.cpp
HEADERS += mainwindow.h \
fshost.h \
call.h \
@ -45,10 +48,15 @@ HEADERS += mainwindow.h \
preferences/prefaccounts.h \
account.h \
widgets/codecwidget.h \
channel.h
channel.h \
debugtools/consolewindow.h \
debugtools/sortfilterproxymodel.h \
debugtools/statedebugdialog.h
FORMS += mainwindow.ui \
preferences/prefdialog.ui \
preferences/accountdialog.ui \
widgets/codecwidget.ui
widgets/codecwidget.ui \
debugtools/consolewindow.ui \
debugtools/statedebugdialog.ui
RESOURCES += resources.qrc
OTHER_FILES += conf/freeswitch.xml

View File

@ -0,0 +1,158 @@
#include "consolewindow.h"
#include "ui_consolewindow.h"
ConsoleWindow::ConsoleWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::ConsoleWindow),
findNext(false)
{
ui->setupUi(this);
sourceModel = new ConsoleModel(this);
model = new SortFilterProxyModel(this);
model->setSourceModel(sourceModel);
model->setFilterKeyColumn(0);
ui->consoleListView->setModel(model);
ui->consoleListView->setColumnWidth(0, 2000);
connect(sourceModel, SIGNAL(beforeInserting()),
this, SLOT(setConditionalScroll()));
connect(sourceModel, SIGNAL(afterInserting()),
this, SLOT(conditionalScroll()));
connect(ui->btnSend, SIGNAL(clicked()),
this, SLOT(cmdSendClicked()));
connect(ui->lineCmd, SIGNAL(textChanged(QString)),
this, SLOT(lineCmdChanged(QString)));
_levelFilter = new QSignalMapper(this);
connect(ui->checkEmerg, SIGNAL(clicked()), _levelFilter, SLOT(map()));
connect(ui->checkAlert, SIGNAL(clicked()), _levelFilter, SLOT(map()));
connect(ui->checkCrit, SIGNAL(clicked()), _levelFilter, SLOT(map()));
connect(ui->checkDebug, SIGNAL(clicked()), _levelFilter, SLOT(map()));
connect(ui->checkError, SIGNAL(clicked()), _levelFilter, SLOT(map()));
connect(ui->checkInfo, SIGNAL(clicked()), _levelFilter, SLOT(map()));
connect(ui->checkNotice, SIGNAL(clicked()), _levelFilter, SLOT(map()));
connect(ui->checkWarn, SIGNAL(clicked()), _levelFilter, SLOT(map()));
_levelFilter->setMapping(ui->checkEmerg, SWITCH_LOG_CONSOLE);
_levelFilter->setMapping(ui->checkAlert, SWITCH_LOG_ALERT);
_levelFilter->setMapping(ui->checkCrit, SWITCH_LOG_CRIT);
_levelFilter->setMapping(ui->checkDebug, SWITCH_LOG_DEBUG);
_levelFilter->setMapping(ui->checkError, SWITCH_LOG_ERROR);
_levelFilter->setMapping(ui->checkInfo, SWITCH_LOG_INFO);
_levelFilter->setMapping(ui->checkNotice, SWITCH_LOG_NOTICE);
_levelFilter->setMapping(ui->checkWarn, SWITCH_LOG_WARNING);
connect(_levelFilter, SIGNAL(mapped(int)), this, SLOT(filterModelLogLevel(int)));
connect(ui->btnFilterClear, SIGNAL(clicked()),
this, SLOT(filterClear()));
connect(ui->lineFilter, SIGNAL(textChanged(QString)),
this, SLOT(filterStringChanged()));
connect(ui->filterCaseSensitivityCheckBox, SIGNAL(toggled(bool)),
this, SLOT(filterStringChanged()));
connect(ui->filterSyntaxComboBox, SIGNAL(currentIndexChanged(int)),
this, SLOT(filterStringChanged()));
connect(ui->filterReverseCheckBox, SIGNAL(toggled(bool)),
this, SLOT(reverseFilterChecked()));
connect(&g_FSHost, SIGNAL(eventLog(QSharedPointer<switch_log_node_t>,switch_log_level_t)), this, SLOT(loggerHandler(QSharedPointer<switch_log_node_t>,switch_log_level_t)));
}
ConsoleWindow::~ConsoleWindow()
{
delete ui;
}
void ConsoleWindow::changeEvent(QEvent *e)
{
QMainWindow::changeEvent(e);
switch (e->type()) {
case QEvent::LanguageChange:
ui->retranslateUi(this);
break;
default:
break;
}
}
void ConsoleWindow::setConditionalScroll()
{
autoScroll = (ui->consoleListView->verticalScrollBar()->maximum() == ui->consoleListView->verticalScrollBar()->value());
}
void ConsoleWindow::conditionalScroll()
{
if (autoScroll)
ui->consoleListView->scrollToBottom();
}
void ConsoleWindow::cmdSendClicked()
{
if (ui->lineCmd->text().isEmpty()) return;
QString cmd = ui->lineCmd->text().split(" ", QString::SkipEmptyParts)[0];
if (cmd.isEmpty()) return;
QStringList split = ui->lineCmd->text().split(" ", QString::SkipEmptyParts);
if (split.isEmpty()) return;
QString args;
for (int i=1; i<split.length(); i++)
{
args += split[i];
if (i!=split.length()-1)
args += " ";
}
QString res;
g_FSHost.sendCmd(cmd.toAscii().data(), args.toAscii().data(), &res);
QStandardItem *item = new QStandardItem(res);
item->setData(SWITCH_LOG_CONSOLE, ConsoleModel::LogLevelRole);
addNewConsoleItem(item);
ui->lineCmd->clear();
}
void ConsoleWindow::lineCmdChanged(QString text)
{
ui->btnSend->setDisabled(text.isEmpty());
}
void ConsoleWindow::filterModelLogLevel(int level)
{
model->setLogLevelFilter(level);
}
void ConsoleWindow::loggerHandler(QSharedPointer<switch_log_node_t> node, switch_log_level_t level)
{
if (level > ui->comboLogLevel->currentIndex()) return;
QString text(node.data()->data);
if (!text.isEmpty())
{
/* Remove \r\n */
QStringList textList = text.split(QRegExp("(\r+)"), QString::SkipEmptyParts);
QString final_str;
for (int line = 0; line<textList.size(); line++)
{
final_str += textList[line];
}
QStringList lines = final_str.split(QRegExp("(\n+)"), QString::SkipEmptyParts);
for (int line = 0; line < lines.size(); ++line)
{
QStandardItem *item = new QStandardItem(lines[line]);
item->setData(level, ConsoleModel::LogLevelRole);
item->setData(node.data()->userdata, ConsoleModel::UUIDRole);
addNewConsoleItem(item);
}
}
}
void ConsoleWindow::addNewConsoleItem(QStandardItem *item)
{
QSettings settings;
settings.beginGroup("Console");
QPalette palette = settings.value(QString("log-level-%1-palette").arg(item->data(Qt::UserRole).toInt())).value<QPalette>();
QFont font = settings.value(QString("log-level-%1-font").arg(item->data(Qt::UserRole).toInt())).value<QFont>();
item->setBackground(palette.base());
item->setForeground(palette.text());
item->setFont(font);
sourceModel->appendRow(item);
}

View File

@ -0,0 +1,56 @@
#ifndef CONSOLEWINDOW_H
#define CONSOLEWINDOW_H
#include <QtGui>
#include "fshost.h"
#include "sortfilterproxymodel.h"
namespace Ui {
class ConsoleWindow;
}
class ConsoleWindow : public QMainWindow {
Q_OBJECT
public:
ConsoleWindow(QWidget *parent = 0);
~ConsoleWindow();
protected:
void changeEvent(QEvent *e);
/*public slots:
void clearConsoleContents();
void saveLogToFile();
void pastebinLog();
void filterLogUUID(QString);
void findText();*/
private slots:
void setConditionalScroll();
void conditionalScroll();
/*void filterClear();
void filterStringChanged();*/
void loggerHandler(QSharedPointer<switch_log_node_t> node, switch_log_level_t level);
void addNewConsoleItem(QStandardItem *item);
void cmdSendClicked();
void lineCmdChanged(QString);
/*void reverseFilterChecked();*/
void filterModelLogLevel(int);
private:
Ui::ConsoleWindow *ui;
ConsoleModel *sourceModel;
QModelIndexList foundItems;
SortFilterProxyModel *model;
/*pastebinDialog *_pastebinDlg;
FindDialog *_findDialog;*/
bool findNext;
bool autoScroll;
QSignalMapper *_levelFilter;
/*void readSettings();
void writeSettings();*/
};
#endif // CONSOLEWINDOW_H

View File

@ -0,0 +1,466 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ConsoleWindow</class>
<widget class="QMainWindow" name="ConsoleWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>696</width>
<height>559</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="maximumSize">
<size>
<width>16777215</width>
<height>118</height>
</size>
</property>
<property name="title">
<string>Filter</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLineEdit" name="lineFilter">
<property name="enabled">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="filterSyntaxComboBox">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToContentsOnFirstShow</enum>
</property>
<item>
<property name="text">
<string>Regular Expression</string>
</property>
</item>
<item>
<property name="text">
<string>Wildcard</string>
</property>
</item>
<item>
<property name="text">
<string>Fixed String</string>
</property>
</item>
<item>
<property name="text">
<string>UUID</string>
</property>
</item>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnFilterClear">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>&amp;Clear</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QCheckBox" name="filterCaseSensitivityCheckBox">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Case sensitive filter</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="filterReverseCheckBox">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Reverse filter</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lblWarningMsg">
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>358</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QSplitter" name="splitter">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<widget class="QWidget" name="layoutWidget_2">
<layout class="QVBoxLayout" name="verticalLayout_3">
<property name="sizeConstraint">
<enum>QLayout::SetMaximumSize</enum>
</property>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="maximumSize">
<size>
<width>120</width>
<height>16777215</height>
</size>
</property>
<property name="title">
<string>Log Level Filter</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QCheckBox" name="checkEmerg">
<property name="text">
<string>Console</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkAlert">
<property name="text">
<string>Alert</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkCrit">
<property name="text">
<string>Critical</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkError">
<property name="text">
<string>Error</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkWarn">
<property name="text">
<string>Warning</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkNotice">
<property name="text">
<string>Notice</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkInfo">
<property name="text">
<string>Info</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkDebug">
<property name="text">
<string>Debug</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>18</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_3">
<property name="maximumSize">
<size>
<width>120</width>
<height>16777215</height>
</size>
</property>
<property name="title">
<string>Loglevel</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QComboBox" name="comboLogLevel">
<property name="enabled">
<bool>true</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
</property>
<property name="currentIndex">
<number>7</number>
</property>
<item>
<property name="text">
<string>Console</string>
</property>
</item>
<item>
<property name="text">
<string>Alert</string>
</property>
</item>
<item>
<property name="text">
<string>Critical</string>
</property>
</item>
<item>
<property name="text">
<string>Error</string>
</property>
</item>
<item>
<property name="text">
<string>Warning</string>
</property>
</item>
<item>
<property name="text">
<string>Notice</string>
</property>
</item>
<item>
<property name="text">
<string>Info</string>
</property>
</item>
<item>
<property name="text">
<string>Debug</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<widget class="QTableView" name="consoleListView">
<property name="autoScroll">
<bool>false</bool>
</property>
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="tabKeyNavigation">
<bool>false</bool>
</property>
<property name="showDropIndicator" stdset="0">
<bool>false</bool>
</property>
<property name="dragDropOverwriteMode">
<bool>false</bool>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::ExtendedSelection</enum>
</property>
<property name="horizontalScrollMode">
<enum>QAbstractItemView::ScrollPerPixel</enum>
</property>
<property name="showGrid">
<bool>false</bool>
</property>
<property name="wordWrap">
<bool>false</bool>
</property>
<property name="cornerButtonEnabled">
<bool>false</bool>
</property>
<attribute name="horizontalHeaderVisible">
<bool>false</bool>
</attribute>
<attribute name="horizontalHeaderCascadingSectionResizes">
<bool>false</bool>
</attribute>
<attribute name="horizontalHeaderHighlightSections">
<bool>false</bool>
</attribute>
<attribute name="horizontalHeaderShowSortIndicator" stdset="0">
<bool>false</bool>
</attribute>
<attribute name="horizontalHeaderStretchLastSection">
<bool>false</bool>
</attribute>
<attribute name="verticalHeaderVisible">
<bool>false</bool>
</attribute>
<attribute name="verticalHeaderCascadingSectionResizes">
<bool>false</bool>
</attribute>
<attribute name="verticalHeaderDefaultSectionSize">
<number>20</number>
</attribute>
<attribute name="verticalHeaderHighlightSections">
<bool>false</bool>
</attribute>
<attribute name="verticalHeaderShowSortIndicator" stdset="0">
<bool>false</bool>
</attribute>
<attribute name="verticalHeaderStretchLastSection">
<bool>false</bool>
</attribute>
</widget>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLineEdit" name="lineCmd">
<property name="enabled">
<bool>true</bool>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>26</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnSend">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>28</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>85</width>
<height>28</height>
</size>
</property>
<property name="text">
<string>Send</string>
</property>
<property name="shortcut">
<string>Return</string>
</property>
<property name="autoDefault">
<bool>true</bool>
</property>
<property name="default">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>696</width>
<height>24</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,116 @@
#include <QtGui>
#include "sortfilterproxymodel.h"
ConsoleModel::ConsoleModel (QObject *parent)
: QAbstractTableModel(parent)
{
QSettings settings;
batchSize = settings.value("Console/batchSize", 200).toInt();
insertionTimer = new QBasicTimer;
insertionTimer->start(0, this);
}
int ConsoleModel::rowCount ( const QModelIndex & parent ) const
{
if (parent.isValid())
return 0;
return _listDisplayModel.count();
}
int ConsoleModel::columnCount ( const QModelIndex & /*parent*/ ) const
{
return 1;
}
QVariant ConsoleModel::data ( const QModelIndex & index, int role ) const
{
if (!index.isValid())
return QVariant();
return _listDisplayModel.at(index.row())->data(role);
}
void ConsoleModel::clear()
{
_listDisplayModel.clear();
reset();
}
void ConsoleModel::appendRow ( QStandardItem* item )
{
_listInsertModel.append(item);
insertionTimer->start(0, this);
}
void ConsoleModel::timerEvent(QTimerEvent *e)
{
if (e->timerId() == insertionTimer->timerId())
{
if (!_listInsertModel.isEmpty())
{
int inserted_items = 0;
int toBeInserted = 0;
if (_listInsertModel.size() < batchSize)
{
toBeInserted = _listInsertModel.size() - 1;
} else {
toBeInserted = batchSize - 1;
}
emit beforeInserting();
beginInsertRows( QModelIndex(), _listDisplayModel.size(), _listDisplayModel.size() + toBeInserted );
while( !_listInsertModel.isEmpty() && inserted_items <= batchSize)
{
_listDisplayModel.append(_listInsertModel.takeFirst());
inserted_items++;
}
endInsertRows();
emit afterInserting();
} else {
insertionTimer->stop();
}
}
}
SortFilterProxyModel::SortFilterProxyModel(QObject *parent)
: QSortFilterProxyModel(parent)
{
reverseFlag = false;
for(int i = 0; i < 8; i++)
loglevels.insert(i, true);
}
void SortFilterProxyModel::toggleReverseFlag()
{
reverseFlag = !reverseFlag;
invalidateFilter();
}
void SortFilterProxyModel::setLogLevelFilter(int level)
{
loglevels.replace(level, loglevels.value(level) == false);
// Let us filter
invalidateFilter();
}
void SortFilterProxyModel::setUUIDFilterLog(QString uuid)
{
_uuid = uuid;
invalidateFilter();
}
bool SortFilterProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
{
QModelIndex index0 = sourceModel()->index(source_row, 0, source_parent);
bool uuidMatch = true;
if (!_uuid.isEmpty())
uuidMatch = (sourceModel()->data(index0, ConsoleModel::UUIDRole).toString() == _uuid);
bool res = (loglevels.value(sourceModel()->data(index0, Qt::UserRole).toInt()) == true
&& sourceModel()->data(index0).toString().contains(filterRegExp())
&& uuidMatch);
if (reverseFlag)
return !res;
else
return res;
}

View File

@ -0,0 +1,97 @@
/*
* Copyright (c) 2007, Anthony Minessale II
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the original author; nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Contributor(s):
*
* Joao Mesquita <jmesquita (at) freeswitch.org>
*
*/
#ifndef SORTFILTERPROXYMODEL_H
#define SORTFILTERPROXYMODEL_H
#include <QSortFilterProxyModel>
#include <QAbstractTableModel>
#include <QVector>
#include <QList>
class QBasicTimer;
class QStandardItem;
class QScrollBar;
class ConsoleModel : public QAbstractTableModel
{
Q_OBJECT
public:
ConsoleModel (QObject *parent = 0);
int rowCount ( const QModelIndex & parent = QModelIndex() ) const;
int columnCount ( const QModelIndex & parent = QModelIndex() ) const;
QVariant data ( const QModelIndex & index, int role = Qt::DisplayRole ) const;
void appendRow ( QStandardItem* item );
void clear();
QList<QStandardItem *> modelData() { return _listDisplayModel; }
enum {
LogLevelRole = Qt::UserRole,
UUIDRole
};
signals:
void beforeInserting();
void afterInserting();
protected:
void timerEvent(QTimerEvent *);
private:
QList<QStandardItem *> _listDisplayModel;
QList<QStandardItem *> _listInsertModel;
int batchSize;
QBasicTimer *insertionTimer;
};
class SortFilterProxyModel : public QSortFilterProxyModel
{
Q_OBJECT
public:
SortFilterProxyModel(QObject *parent = 0);
void setLogLevelFilter(int level);
void setUUIDFilterLog(QString uuid);
void toggleReverseFlag();
protected:
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const;
private:
QVector<bool> loglevels;
QString _uuid;
bool reverseFlag;
};
#endif // SORTFILTERPROXYMODEL_H

View File

@ -0,0 +1,76 @@
#include "statedebugdialog.h"
#include "ui_statedebugdialog.h"
StateDebugDialog::StateDebugDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::StateDebugDialog)
{
ui->setupUi(this);
connect(&g_FSHost, SIGNAL(newEvent(QSharedPointer<switch_event_t>)), this, SLOT(newEvent(QSharedPointer<switch_event_t>)));
connect(ui->listUUID, SIGNAL(itemSelectionChanged()), this, SLOT(currentUuidChanged()));
connect(ui->listEvents, SIGNAL(itemSelectionChanged()), this, SLOT(currentEventsChanged()));
}
StateDebugDialog::~StateDebugDialog()
{
delete ui;
}
void StateDebugDialog::changeEvent(QEvent *e)
{
QDialog::changeEvent(e);
switch (e->type()) {
case QEvent::LanguageChange:
ui->retranslateUi(this);
break;
default:
break;
}
}
void StateDebugDialog::newEvent(QSharedPointer<switch_event_t>event)
{
/* We don't want to keep track of events that are not calls at this moment */
if (QString(switch_event_get_header_nil(event.data(), "Unique-ID")).isEmpty())
return;
QString uuid(switch_event_get_header_nil(event.data(), "Unique-ID"));
if (!_events.contains(uuid))
{
QList<QSharedPointer<switch_event_t> > tmpListEvents;
tmpListEvents.append(event);
_events.insert(uuid, tmpListEvents);
ui->listUUID->addItem(new QListWidgetItem(uuid));
}
else
{
QList<QSharedPointer<switch_event_t> > tmpListEvents = _events.value(uuid);
tmpListEvents.append(event);
_events.insert(uuid, tmpListEvents);
}
}
void StateDebugDialog::currentUuidChanged()
{;
ui->listEvents->clear();
ui->listDetails->clear();
QString uuid = ui->listUUID->currentItem()->text();
foreach(QSharedPointer<switch_event_t> e, _events.value(uuid))
{
ui->listEvents->addItem(new QListWidgetItem(switch_event_name(e.data()->event_id)));
}
}
void StateDebugDialog::currentEventsChanged()
{
ui->listDetails->clear();
int r = ui->listEvents->currentRow();
QString uuid = ui->listUUID->currentItem()->text();
QList<QSharedPointer<switch_event_t> > tmpListEvents = _events.value(uuid);
QSharedPointer<switch_event_t> e = tmpListEvents.at(r);
for(switch_event_header_t* h = e.data()->headers; h != e.data()->last_header; h = h->next)
{
ui->listDetails->addItem(new QListWidgetItem(QString("%1 = %2").arg(h->name, h->value)));
}
}

View File

@ -0,0 +1,30 @@
#ifndef STATEDEBUGDIALOG_H
#define STATEDEBUGDIALOG_H
#include <QtGui>
#include "fshost.h"
namespace Ui {
class StateDebugDialog;
}
class StateDebugDialog : public QDialog {
Q_OBJECT
public:
StateDebugDialog(QWidget *parent = 0);
~StateDebugDialog();
private slots:
void newEvent(QSharedPointer<switch_event_t> event);
void currentUuidChanged();
void currentEventsChanged();
protected:
void changeEvent(QEvent *e);
private:
Ui::StateDebugDialog *ui;
QHash<QString, QList<QSharedPointer<switch_event_t> > > _events;
};
#endif // STATEDEBUGDIALOG_H

View File

@ -0,0 +1,79 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>StateDebugDialog</class>
<widget class="QDialog" name="StateDebugDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>804</width>
<height>235</height>
</rect>
</property>
<property name="windowTitle">
<string>Debug Events</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QSplitter" name="splitter">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<widget class="QWidget" name="layoutWidget">
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>UUID</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QListWidget" name="listUUID"/>
</item>
</layout>
</widget>
<widget class="QWidget" name="layoutWidget">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>EVENTS</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QListWidget" name="listEvents"/>
</item>
</layout>
</widget>
<widget class="QWidget" name="layoutWidget">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>DETAILS</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QListWidget" name="listDetails"/>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -43,7 +43,10 @@ FSHost::FSHost(QObject *parent) :
switch_core_set_globals();
qRegisterMetaType<QSharedPointer<Call> >("QSharedPointer<Call>");
qRegisterMetaType<QSharedPointer<Call> >("QSharedPointer<Channel>");
qRegisterMetaType<QSharedPointer<switch_event_t> >("QSharedPointer<switch_event_t>");
qRegisterMetaType<QSharedPointer<switch_log_node_t> >("QSharedPointer<switch_log_node_t>");
qRegisterMetaType<switch_log_level_t>("switch_log_level_t");
qRegisterMetaType<QSharedPointer<Channel> >("QSharedPointer<Channel>");
qRegisterMetaType<QSharedPointer<Account> >("QSharedPointer<Account>");
connect(this, SIGNAL(loadedModule(QString,QString)), this, SLOT(minimalModuleLoaded(QString,QString)));
@ -115,6 +118,11 @@ void FSHost::createFolders()
}
}
void FSHost::generalLoggerHandler(QSharedPointer<switch_log_node_t>node, switch_log_level_t level)
{
emit eventLog(node, level);
}
void FSHost::run(void)
{
switch_core_flag_t flags = SCF_USE_SQL | SCF_USE_AUTO_NAT;
@ -150,6 +158,7 @@ void FSHost::run(void)
emit coreLoadingError(err);
}
switch_log_bind_logger(loggerHandler, SWITCH_LOG_DEBUG, SWITCH_FALSE);
emit ready();
/* Go into the runtime loop. If the argument is true, this basically sets runtime.running = 1 and loops while that is set
@ -172,6 +181,8 @@ void FSHost::generalEventHandler(QSharedPointer<switch_event_t>event)
{
QString uuid = switch_event_get_header_nil(event.data(), "Unique-ID");
emit newEvent(event);
switch(event.data()->event_id) {
case SWITCH_EVENT_CHANNEL_CREATE: /*1A - 17B*/
{

View File

@ -45,6 +45,7 @@ public:
explicit FSHost(QObject *parent = 0);
switch_status_t sendCmd(const char *cmd, const char *args, QString *res);
void generalEventHandler(QSharedPointer<switch_event_t>event);
void generalLoggerHandler(QSharedPointer<switch_log_node_t>node, switch_log_level_t level);
QSharedPointer<Call> getCallByUUID(QString uuid) { return _active_calls.value(uuid); }
QSharedPointer<Call> getCurrentActiveCall();
QList<QSharedPointer<Account> > getAccounts() { return _accounts.values(); }
@ -64,6 +65,11 @@ signals:
void loadedModule(QString, QString);
void ready(void);
/* Logging signals */
void eventLog(QSharedPointer<switch_log_node_t>, switch_log_level_t);
void newEvent(QSharedPointer<switch_event_t>);
/* Call signals */
void ringing(QSharedPointer<Call>);
void answered(QSharedPointer<Call>);
@ -121,7 +127,7 @@ extern FSHost g_FSHost;
/*
Used to match callback from fs core. We dup the event and call the class
method callback to make use of the signal/slot infrastructure.
*/
*/
static void eventHandlerCallback(switch_event_t *event)
{
switch_event_t *clone = NULL;
@ -131,4 +137,15 @@ static void eventHandlerCallback(switch_event_t *event)
}
}
/*
Used to propagate logs on the application
*/
static switch_status_t loggerHandler(const switch_log_node_t *node, switch_log_level_t level)
{
switch_log_node_t *clone = switch_log_node_dup(node);
QSharedPointer<switch_log_node_t> l(clone);
g_FSHost.generalLoggerHandler(l, level);
return SWITCH_STATUS_SUCCESS;
}
#endif // FSHOST_H

View File

@ -36,7 +36,10 @@
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow),
preferences(NULL)
preferences(NULL),
_consoleWindow(NULL),
_stateDebugDialog(NULL)
{
ui->setupUi(this);
@ -100,6 +103,8 @@ MainWindow::MainWindow(QWidget *parent) :
connect(ui->tableCalls, SIGNAL(itemDoubleClicked(QTableWidgetItem*)), this, SLOT(callTableDoubleClick(QTableWidgetItem*)));
connect(ui->action_Preferences, SIGNAL(triggered()), this, SLOT(prefTriggered()));
connect(ui->action_Exit, SIGNAL(triggered()), this, SLOT(close()));
connect(ui->actionConsole, SIGNAL(triggered()), this, SLOT(debugConsoleTriggered()));
connect(ui->actionEvents, SIGNAL(triggered()), this, SLOT(debugEventsTriggered()));
connect(ui->actionAbout, SIGNAL(triggered()), this, SLOT(showAbout()));
connect(ui->actionSetDefaultAccount, SIGNAL(triggered(bool)), this, SLOT(setDefaultAccount()));
connect(sysTray, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(sysTrayActivated(QSystemTrayIcon::ActivationReason)));
@ -151,6 +156,28 @@ void MainWindow::setDefaultAccount()
settings.endGroup();
}
void MainWindow::debugEventsTriggered()
{
if (!_stateDebugDialog)
_stateDebugDialog = new StateDebugDialog();
_stateDebugDialog->raise();
_stateDebugDialog->show();
_stateDebugDialog->activateWindow();
}
void MainWindow::debugConsoleTriggered()
{
if (!_consoleWindow)
_consoleWindow = new ConsoleWindow();
_consoleWindow->raise();
_consoleWindow->show();
_consoleWindow->activateWindow();
}
void MainWindow::prefTriggered()
{
if (!preferences)

View File

@ -40,6 +40,8 @@
#include <call.h>
#include <account.h>
#include "preferences/prefdialog.h"
#include "debugtools/consolewindow.h"
#include "debugtools/statedebugdialog.h"
namespace Ui {
class MainWindow;
@ -80,11 +82,15 @@ private slots:
void accountStateChanged(QSharedPointer<Account>);
void sysTrayActivated(QSystemTrayIcon::ActivationReason reason);
void updateCallTimers();
void debugConsoleTriggered();
void debugEventsTriggered();
private:
Ui::MainWindow *ui;
QSignalMapper *dialpadMapper;
PrefDialog *preferences;
ConsoleWindow *_consoleWindow;
StateDebugDialog * _stateDebugDialog;
QSystemTrayIcon *sysTray;
QTimer *callTimer;
};

View File

@ -375,7 +375,21 @@
</property>
<addaction name="actionAbout"/>
</widget>
<widget class="QMenu" name="menuTools">
<property name="title">
<string>&amp;Tools</string>
</property>
<widget class="QMenu" name="menuDebug">
<property name="title">
<string>&amp;Debug</string>
</property>
<addaction name="actionConsole"/>
<addaction name="actionEvents"/>
</widget>
<addaction name="menuDebug"/>
</widget>
<addaction name="menu_File"/>
<addaction name="menuTools"/>
<addaction name="menuHelp"/>
</widget>
<widget class="QToolBar" name="mainToolBar">
@ -410,6 +424,16 @@
<string>Set the default account for dialing out.</string>
</property>
</action>
<action name="actionConsole">
<property name="text">
<string>Console</string>
</property>
</action>
<action name="actionEvents">
<property name="text">
<string>Events</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>