Merged client logic, qt library and ui changes from client branch into trunk.

git-svn-id: http://voip.null.ro/svn/yate@3933 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
marian 2010-12-08 14:37:24 +00:00
parent 6a34e5b3b9
commit b924220061
149 changed files with 24220 additions and 5199 deletions

View File

@ -29,8 +29,6 @@ LIBS :=
MENUFILES :=
DESKFILES :=
QTCLIENT := qt4/libqt4client.a
ifneq (@HAVE_QT4@,no)
SUBDIRS := $(SUBDIRS) qt4
PROGS := $(PROGS) yate-qt4
@ -147,12 +145,9 @@ do-all do-strip do-clean do-install do-uninstall:
Makefile: @srcdir@/Makefile.in $(MKDEPS)
cd .. && ./config.status
yate-%: @srcdir@/main-%.cpp $(MKDEPS) ../libyate.so $(INCFILES)
yate-%: @srcdir@/main-%.cpp $(MKDEPS) ../libyate.so ../libyateqt4.so $(INCFILES)
$(COMPILE) -o $@ $(LOCALFLAGS) $< $(LDFLAGS) $(LIBTHR) $(LOCALLIBS) $(YATELIBS)
yate-qt4: $(QTCLIENT)
yate-qt4:
yate-qt4: LOCALFLAGS = $(QT4_INC)
yate-qt4: LOCALLIBS = $(QTCLIENT) $(QT4_LIB)
$(QTCLIENT):
$(MAKE) -C qt4
yate-qt4: LOCALLIBS = -lyateqt4 $(QT4_LIB)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 206 B

After

Width:  |  Height:  |  Size: 565 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 313 B

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 484 B

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -14,16 +14,24 @@ QT4_LIB_NET := @QT4_LIB_NET@
DEFS:=
INCLUDES:=-I. -I@srcdir@ -I@top_srcdir@ $(QT4_INC)
CXXFLAGS:=$(CXXFLAGS) @MODULE_CPPFLAGS@ @INLINE_FLAGS@
CFLAGS := @CFLAGS@ @MODULE_CPPFLAGS@ @INLINE_FLAGS@
LDFLAGS:= @LDFLAGS@
SONAME_OPT := @SONAME_OPT@
YATELIBS := -L../.. -lyate @LIBS@
INCFILES := @top_srcdir@/yateclass.h @top_srcdir@/yatecbase.h @srcdir@/qt4client.h
PROJECT = libqt4client.a
PROGS=
LIBS =
SOURCES = qt4client.cpp
OBJECTS = $(SOURCES:.cpp=.o) qt4client.moc.o
OBJS = $(SOURCES:.cpp=.o) qt4client.moc.o
LIBD_DEV:= libyateqt4.so
LIBD_VER:= $(LIBD_DEV).@PACKAGE_VERSION@
LIBD:= ../../$(LIBD_VER) ../../$(LIBD_DEV)
COMPILE = $(CXX) $(DEFS) $(DEBUG) $(INCLUDES) $(CXXFLAGS)
LOCALFLAGS =
LOCALLIBS =
COMPILE = $(CXX) $(DEFS) $(DEBUG) $(INCLUDES) $(CFLAGS)
LINK = $(CXX) $(LDFLAGS)
ifneq (x@QT4_VER@,x)
DEFS := $(DEFS) -DQT4_VER=@QT4_VER@
@ -35,23 +43,25 @@ exec_prefix = @exec_prefix@
# include optional local make rules
-include YateLocal.mak
.PHONY: all debug ddebug xdebug clean install uninstall
all: $(PROJECT)
.PHONY: all debug ddebug xdebug
all: $(LIBS) $(LIBD) $(PROGS)
debug:
$(MAKE) all DEBUG=-g3
$(MAKE) all DEBUG=-g3 MODSTRIP=
ddebug:
$(MAKE) all DEBUG='-g3 -DDEBUG'
$(MAKE) all DEBUG='-g3 -DDEBUG' MODSTRIP=
xdebug:
$(MAKE) all DEBUG='-g3 -DXDEBUG'
$(MAKE) all DEBUG='-g3 -DXDEBUG' MODSTRIP=
.PHONY: strip
strip: all
strip --strip-debug --discard-locals $(PROGS)
.PHONY: clean
clean:
@-$(RM) $(PROJECT) $(OBJECTS)
$(PROJECT): $(OBJECTS)
$(AR) rcs $@ $^
@-$(RM) $(PROGS) $(LIBS) $(LIBD) $(OBJS) core 2>/dev/null
%.o: @srcdir@/%.cpp $(INCFILES)
$(COMPILE) -c $<
@ -64,3 +74,9 @@ $(PROJECT): $(OBJECTS)
Makefile: @srcdir@/Makefile.in ../../config.status
cd ../.. && ./config.status
../../$(LIBD_VER): $(OBJS)
$(LINK) -o $@ $(SONAME_OPT)$(LIBD_VER) $^ $(QT4_LIB) $(YATELIBS)
../../$(LIBD_DEV): ../../$(LIBD_VER)
cd ../.. && ln -sf $(LIBD_VER) $(LIBD_DEV)

File diff suppressed because it is too large Load Diff

View File

@ -68,6 +68,8 @@ class QtClient; // The QT based client
class QtDriver; // The QT based telephony driver
class QtWindow; // A QT window
class QtDialog; // A custom modal dialog
class QtUIWidgetItemProps; // Widget container item properties
class QtUIWidget; // A widget container
class QtCustomObject; // A custom QT object
class QtCustomWidget; // A custom QT widget
class QtTable; // A custom QT table widget
@ -120,6 +122,22 @@ class YQT4_API QtClient : public Client
{
friend class QtWindow;
public:
/**
* Generic position flags
*/
enum QtClientPos {
PosNone = 0,
PosLeft = 0x01,
PosRight = 0x02,
PosTop = 0x04,
PosBottom = 0x08,
// Corners
CornerTopLeft = PosTop | PosLeft,
CornerTopRight = PosTop | PosRight,
CornerBottomLeft = PosBottom | PosLeft,
CornerBottomRight = PosBottom | PosRight,
};
QtClient();
virtual ~QtClient();
virtual void run();
@ -324,6 +342,13 @@ public:
*/
static void copyParams(QStringList& dest, const NamedList& src);
/**
* Build QObject properties from list
* @param obj The object
* @param props Comma separated list of properties. Format: name=type
*/
static void buildProps(QObject* obj, const String& props);
/**
* Build custom UI widgets from frames owned by a widget
* @param parent Parent widget
@ -411,6 +436,28 @@ public:
static bool connectObjects(QObject* sender, const char* signal,
QObject* receiver, const char* slot);
/**
* Safely delete a QObject. Disconnect it, reset its parent, calls its deleteLater() method
* @param obj The object to delete
*/
static void deleteLater(QObject* obj);
/**
* Retrieve unavailable space position (if any) in the screen containing a given widget.
* The positions are set using the difference between screen geometry and available geometry
* @param w The widget
* @param pos Unavailable screen space if any (QtClientPos combination)
* @return Valid pointer to global desktop widget on success
*/
static QDesktopWidget* getScreenUnavailPos(QWidget* w, int& pos);
/**
* Move a window to a specified position
* @param w The window to move
* @param pos A corner position
*/
static void moveWindow(QtWindow* w, int pos);
protected:
virtual void loadWindows(const char* file = 0);
private:
@ -617,6 +664,20 @@ public:
return QtClient::connectObjects(b,SIGNAL(toggled(bool)),this,SLOT(toggled(bool)));
}
/**
* Connect an object's text changed signal to window's slot
* @param obj The object to connect
* @return True on success
*/
bool connectTextChanged(QObject* obj);
/**
* Notify text changed to the client
* @param obj The object sending the notification
* @param text Optional object text
*/
void notifyTextChanged(QObject* obj, const QString& text = QString());
/**
* Load a widget from file
* @param fileName UI filename to load
@ -641,6 +702,13 @@ public:
inline QtWindow* parentWindow() const
{ return qobject_cast<QtWindow*>(parentWidget() ? parentWidget()->window() : 0); }
/**
* Check if this window is shown normal (not maximixed, minimized or full screen)
* @return True if the window is not maximixed, minimized or full screen
*/
inline bool isShownNormal() const
{ return !(isMaximized() || isMinimized() || isFullScreen()); }
protected:
// Notify client on selection changes
inline bool select(const String& name, const String& item,
@ -672,7 +740,10 @@ public slots:
// Choose file window was cancelled
void chooseFileRejected();
// Text changed slot. Notify the client
void textChanged(const QString& text);
void textChanged(const QString& text)
{ notifyTextChanged(sender(),text); }
void textChanged()
{ notifyTextChanged(sender()); }
private slots:
void openUrl(const QString& link);
@ -681,10 +752,8 @@ protected:
virtual void doPopulate();
virtual void doInit();
// Methods inherited from QWidget
virtual void moveEvent(QMoveEvent* event)
{ updatePosSize(); }
virtual void resizeEvent(QResizeEvent* event)
{ updatePosSize(); }
virtual void moveEvent(QMoveEvent* event);
virtual void resizeEvent(QResizeEvent* event);
virtual bool event(QEvent* ev);
virtual void mousePressEvent(QMouseEvent* event);
virtual void mouseReleaseEvent(QMouseEvent* event);
@ -695,8 +764,6 @@ protected:
if (handleContextMenuEvent(ev,wndWidget()))
ev->accept();
}
// Update window position and size
void updatePosSize();
// Get the widget with this window's content
inline QWidget* wndWidget()
{ return findChild<QWidget*>(m_widget); }
@ -707,8 +774,8 @@ protected:
String m_oldId; // Old id used to retreive the config section in .rc
int m_x;
int m_y;
int m_width;
int m_height;
int m_width; // Client area width
int m_height; // Client area height
bool m_maximized;
bool m_mainWindow; // Main window flag: close app when this window is closed
QString m_widget; // The widget with window's content
@ -795,18 +862,399 @@ protected slots:
protected:
// Destroy the dialog
virtual void closeEvent(QCloseEvent* event);
// Destroy the dialog
virtual void reject();
String m_notifyOnClose; // Action to notify when closed
QString m_context; // Dialog context
};
/**
* This class holds data about a widget container item
* @short Widget container item properties
*/
class QtUIWidgetItemProps : public String
{
public:
/**
* Constructor
* @param type Item type
*/
explicit inline QtUIWidgetItemProps(const String& type)
: String(type)
{}
String m_ui; // Item UI file
String m_styleSheet; // Item style sheet when not selected
String m_selStyleSheet; // Item selected style
};
/**
* This class holds a basic widget container with functions to rename children
* @short A widget container
*/
class YQT4_API QtUIWidget : public UIWidget
{
YCLASS(QtUIWidget,UIWidget)
public:
/**
* Constructor
* @param name Object name
* @param params Object parameters
* @param parent Optional parent
*/
inline QtUIWidget(const char* name)
: UIWidget(name)
{}
/**
* Build a child name from this one
* @param buf Destination buffer
* @param item Child name
* @return The destination buffer
*/
inline String& buildChildName(String& buf, const String& item)
{ return buildChildName(buf,name(),item); }
/**
* Build a container QString child name
* @param item Child name
* @return QString child name
*/
inline QString buildQChildName(const String& item)
{ return buildQChildName(name(),item); }
/**
* Retrieve item type definition
* @param type Item type name
* @return QtUIWidgetItemProps pointer or 0
*/
inline QtUIWidgetItemProps* getItemProps(const String& type) {
ObjList* o = m_itemProps.find(type);
return o ? static_cast<QtUIWidgetItemProps*>(o->get()) : 0;
}
/**
* Retrieve item type definition from [type:]value. Create it if not found
* @param in Input string
* @param value Item property value
* @return QtUIWidgetItemProps pointer or 0
*/
virtual QtUIWidgetItemProps* getItemProps(QString& in, String& value);
/**
* Retrieve the list of properties to save
* @return The list of properties to save
*/
QStringList saveProps()
{ return m_saveProps; }
/**
* Set the list of properties to save
* @param list The new list of properties to save
*/
void setSaveProps(QStringList list)
{ m_saveProps = list; }
/**
* Retrieve a QObject descendent of this object
* @return QObject pointer or 0
*/
virtual QObject* getQObject()
{ return 0; }
/**
* Retrieve the window owning this object
* @return QtWindow pointer or 0
*/
virtual QtWindow* getWindow()
{ return QtClient::parentWindow(getQObject()); }
/**
* Set widget's parameters.
* Handle an 'applyall' parameter carrying a NamedList to apply to all items
* @param params List of parameters
* @return True if all parameters could be set
*/
virtual bool setParams(const NamedList& params);
/**
* Retrieve a QObject list containing container items
* @return The list of container items
*/
virtual QList<QObject*> getContainerItems()
{ return QList<QObject*>(); }
/**
* Find an item widget by id
* @param id Item id
* @return QWidget pointer or 0
*/
virtual QWidget* findItem(const String& id);
/**
* Apply a list of parameters to all container items
* @return The list of parameters to apply
*/
virtual void applyAllParams(const NamedList& params);
/**
* Retrieve the object identity from '_yate_identity' property or name
* Retrieve the object item from '_yate_widgetlistitem' property.
* Set 'identity' to object_identity[:item_name]
* @param obj The object
* @param identiy Destination buffer
*/
virtual void getIdentity(QObject* obj, String& identity);
/**
* Update an item object and children from a list a parameters
* @param parent Parent object
* @param params The list of parameters
* @return True on success
*/
virtual bool setParams(QObject* parent, const NamedList& params);
/**
* Get an item object's parameters
* @param parent The object
* @param params Parameter list
* @return True on success
*/
virtual bool getParams(QObject* parent, NamedList& params);
/**
* Retrieve object slots
* @param actionSlot Action (triggerred) slot
* @param toggleSlot Toggled slot
* @param selectSlot Selection change slot
*/
virtual void getSlots(String& actionSlot, String& toggleSlot, String& selectSlot) {
actionSlot = SLOT(itemChildAction());
toggleSlot = SLOT(itemChildToggle(bool));
selectSlot = SLOT(itemChildSelect());
}
/**
* Select an item by its index
* @param index Item index to select
* @return True on success
*/
virtual bool setSelectIndex(int index)
{ return false; }
/**
* Retrieve the 0 based index of the current item
* @return The index of the current item (-1 on error or container empty)
*/
virtual int currentItemIndex()
{ return -1; }
/**
* Retrieve the number of items in container
* @return The number of items in container (-1 on error)
*/
virtual int itemCount()
{ return -1; }
/**
* Build a child's widget menu. Connect actions to container slots
* @param w The widget
* @param params Menu params
* @param child Optional widget child target
* @param set True to set the menu, false to build it and just return it
* @return QMenu pointer or 0
*/
QMenu* buildWidgetItemMenu(QWidget* w, const NamedList* params,
const String& child = String::empty(), bool set = true);
/**
* Build a container child name
* @param buf Destination buffer
* @param name Container widget name
* @param item Child name
* @return The destination buffer
*/
static inline String& buildChildName(String& buf, const String& name,
const String& item) {
buf = name + "_" + item;
return buf;
}
/**
* Build a container child name
* @param name Container widget name
* @param item Child name
* @return QString child name
*/
static inline QString buildQChildName(const QString& name, const QString& item)
{ return name + "_" + item; }
/**
* Build a container QString child name
* @param name Container widget name
* @param item Child name
* @return QString child name
*/
static inline QString buildQChildName(const String& name, const String& item) {
String buf;
return QtClient::setUtf8(buildChildName(buf,name,item));
}
/**
* Set the list item id property to a list item object
* @param obj The object
* @param item Item id property value
*/
static inline void setListItemIdProp(QObject* obj, const QString& item)
{ obj->setProperty("_yate_widgetlistitemid",QVariant(item)); }
/**
* Retrieve the list item id property from a list item object
* @param obj The object
* @param item Destination string
*/
static inline void getListItemIdProp(QObject* obj, String& item)
{ QtClient::getProperty(obj,"_yate_widgetlistitemid",item); }
/**
* Set the list item property for an item's child object
* @param obj The object
* @param item Item property value
*/
static inline void setListItemProp(QObject* obj, const QString& item)
{ obj->setProperty("_yate_widgetlistitem",QVariant(item)); }
/**
* Retrieve the list item property from an item's child object
* @param obj The object
* @param item Destination string
*/
static inline void getListItemProp(QObject* obj, String& item)
{ QtClient::getProperty(obj,"_yate_widgetlistitem",item); }
/**
* Retrieve the top level QtUIWidget container parent of an object
* @param obj The object
* @return QtUIWidget pointer or 0 if not found
*/
static QtUIWidget* container(QObject* obj);
protected:
/**
* Default constructor
*/
QtUIWidget()
{}
/**
* Initialize navigation controls
* @param params Parameter list
*/
void initNavigation(const NamedList& params);
/**
* Update navigation controls
*/
void updateNavigation();
/**
* Trigger a custom action from an item. Build a list of parameters containing
* the 'item' and the 'list' object identity
* @param item The item id
* @param action The action name to trigger
* @param sender Optional sender (set it to 0 to use getQObject())
*/
void triggerAction(const String& item, const String& action, QObject* sender = 0);
/**
* Handle a child's action. Retrieve the object identity (using getIdentity()) and
* notify the action 'sender_identity:sender_item_name' to the client
* Internally handle next/prev actions if set
* @param sender The sender
*/
virtual void onAction(QObject* sender);
/**
* Handle a child's action. Retrieve the object identity (using getIdentity()) and
* notify the toggled 'sender_identity:sender_item_name' event to the client
* @param sender The sender
* @param on Toggle status
*/
virtual void onToggle(QObject* sender, bool on);
/**
* Handle a child's selection change. Retrieve the object identity and
* notify the select 'sender_identity:sender_item_name' event to the client.
* @param sender The sender
* @param item Optional selected item if any. Set it to 0 to detect it
*/
virtual void onSelect(QObject* sender, const String* item = 0);
/**
* Load an item's widget. Rename children.
* Set '_yate_widgetlistitemid' widget property to given name.
* Set '_yate_widgetlistitem' to item for each child.
* Connect signals for children not having a '_yate_autoconnect' property set to false.
* Install event filter for children with '_yate_filterevents' property set to true.
* @param parent Parent widget
* @param name Widget name
* @param ui UI file to load
* @return QWidget pointer or 0
*/
QWidget* loadWidget(QWidget* parent, const String& name, const String& ui);
/**
* Load an item's widget using a given type
* @param parent Parent widget
* @param name Widget name
* @param type Item type
* @return QWidget pointer or 0
*/
inline QWidget* loadWidgetType(QWidget* parent, const String& name, const String& type) {
QtUIWidgetItemProps* p = getItemProps(type);
if (p && p->m_ui)
return loadWidget(parent,name,p->m_ui);
return 0;
}
/**
* Apply a QWidget style sheet. Replace ${name} with widget name in style
* @param name The widget
* @param style The style sheet to apply
*/
void applyWidgetStyle(QWidget* w, const String& style);
/**
* Filter key press events. Retrieve an action associated with the key.
* Check if the object is allowed to process the key.
* Raise the action
* @param obj The object
* @param event QKeyEvent event to process
* @param filter Filter key or let the object process it
* @return True if processed, false if no key was filtered
*/
bool filterKeyEvent(QObject* watched, QKeyEvent* event, bool& filter);
ObjList m_itemProps;
QStringList m_saveProps; // List of properties to be automatically
// saved/restored when window owning
// this object is initialized/destroyed
// Navigation
String m_prev; // Goto previous item action
String m_next; // Goto next item action
String m_info; // Info widget: current index, total ...
String m_infoFormat; // Data to be displayed in info
String m_title; // Current item title widget name
};
/**
* This class encapsulates a custom QT object
* @short A custom QT object
*/
class YQT4_API QtCustomObject : public QObject, public UIWidget
class YQT4_API QtCustomObject : public QObject, public QtUIWidget
{
YCLASS(QtCustomObject,UIWidget)
YCLASS(QtCustomObject,QtUIWidget)
Q_CLASSINFO("QtCustomObject","Yate")
Q_OBJECT
public:
@ -816,9 +1264,16 @@ public:
* @param parent Optional parent object
*/
inline QtCustomObject(const char* name, QObject* parent = 0)
: QObject(parent), UIWidget(name)
: QObject(parent), QtUIWidget(name)
{ setObjectName(name); }
/**
* Retrieve a QObject from this one
* @return QObject pointer
*/
virtual QObject* getQObject()
{ return static_cast<QObject*>(this); }
/**
* Parent changed notification
*/
@ -833,9 +1288,9 @@ private:
* This class encapsulates a custom QT widget
* @short A custom QT widget
*/
class YQT4_API QtCustomWidget : public QWidget, public UIWidget
class YQT4_API QtCustomWidget : public QWidget, public QtUIWidget
{
YCLASS(QtCustomWidget,UIWidget)
YCLASS(QtCustomWidget,QtUIWidget)
Q_CLASSINFO("QtCustomWidget","Yate")
Q_OBJECT
public:
@ -845,9 +1300,16 @@ public:
* @param parent Optional parent widget
*/
inline QtCustomWidget(const char* name, QWidget* parent = 0)
: QWidget(parent), UIWidget(name)
: QWidget(parent), QtUIWidget(name)
{ setObjectName(name); }
/**
* Retrieve a QObject from this one
* @return QObject pointer
*/
virtual QObject* getQObject()
{ return static_cast<QObject*>(this); }
private:
QtCustomWidget() {} // No default constructor
};
@ -856,9 +1318,9 @@ private:
* This class encapsulates a custom QT table
* @short A custom QT table widget
*/
class YQT4_API QtTable : public QTableWidget, public UIWidget
class YQT4_API QtTable : public QTableWidget, public QtUIWidget
{
YCLASS(QtTable,UIWidget)
YCLASS(QtTable,QtUIWidget)
Q_CLASSINFO("QtTable","Yate")
Q_OBJECT
public:
@ -868,13 +1330,50 @@ public:
* @param parent Optional parent widget
*/
inline QtTable(const char* name, QWidget* parent = 0)
: QTableWidget(parent), UIWidget(name)
: QTableWidget(parent), QtUIWidget(name)
{ setObjectName(name); }
/**
* Retrieve a QObject from this one
* @return QObject pointer
*/
virtual QObject* getQObject()
{ return static_cast<QObject*>(this); }
private:
QtTable() {} // No default constructor
};
/**
* This class encapsulates a custom QT tree
* @short A custom QT tree widget
*/
class YQT4_API QtTree : public QTreeWidget, public QtUIWidget
{
YCLASS(QtTree,QtUIWidget)
Q_CLASSINFO("QtTree","Yate")
Q_OBJECT
public:
/**
* Constructor
* @param name Tree's name
* @param parent Optional parent widget
*/
inline QtTree(const char* name, QWidget* parent = 0)
: QTreeWidget(parent), QtUIWidget(name)
{ setObjectName(name); }
/**
* Retrieve a QObject from this one
* @return QObject pointer
*/
virtual QObject* getQObject()
{ return static_cast<QObject*>(this); }
private:
QtTree() {} // No default constructor
};
/**
* QT specific sound
* @short A QT client sound
@ -891,7 +1390,7 @@ public:
*/
inline QtSound(const char* name, const char* file, const char* device = 0)
: ClientSound(name,file,device), m_sound(0)
{}
{ m_native = true; }
protected:
virtual bool doStart();

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -103,7 +103,7 @@ PROGS := $(PROGS) client/coreaudio.yate
endif
ifneq (@HAVE_QT4@,no)
PROGS := $(PROGS) qt4/updater.yate
PROGS := $(PROGS) qt4/updater.yate qt4/customtable.yate qt4/customtext.yate qt4/customtree.yate qt4/widgetlist.yate
endif
ifneq (@HAVE_ZAP@,no)
@ -342,6 +342,14 @@ qt4/updater.yate: qt4/updater.moc
qt4/updater.yate: LOCALFLAGS = $(QT4_INC_NET)
qt4/updater.yate: LOCALLIBS = $(QT4_LIB_NET)
qt4/customtable.yate: qt4/customtable.moc
qt4/customtext.yate: qt4/customtext.moc
qt4/customtree.yate: qt4/customtree.moc
qt4/widgetlist.yate: qt4/widgetlist.moc
qt4/customtable.yate qt4/customtext.yate qt4/customtree.yate qt4/widgetlist.yate: ../libyateqt4.so
qt4/customtable.yate qt4/customtext.yate qt4/customtree.yate qt4/widgetlist.yate: LOCALFLAGS = $(QT4_INC_NET)
qt4/customtable.yate qt4/customtext.yate qt4/customtree.yate qt4/widgetlist.yate: LOCALLIBS = $(QT4_LIB_NET) -lyateqt4
server/sipfeatures.yate: ../libs/yxml/libyatexml.a
server/sipfeatures.yate: LOCALFLAGS = -I@top_srcdir@/libs/yxml
server/sipfeatures.yate: LOCALLIBS = -L../libs/yxml -lyatexml
@ -386,6 +394,9 @@ server/ysnmpagent.yate: LOCALLIBS = -L../libs/yasn -lyasn -L../libs/ysnmp -lysnm
../libs/ypbx/libyatepbx.a:
$(MAKE) -C ../libs/ypbx
../libyateqt4.so:
$(MAKE) -C ../clients/qt4
../libs/yasn/libyasn.a:
$(MAKE) -C ../libs/yasn

704
modules/qt4/customtable.cpp Normal file
View File

@ -0,0 +1,704 @@
/**
* customtable.cpp
* This file is part of the YATE Project http://YATE.null.ro
*
* Custom table implementation
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2010 Null Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "customtable.h"
using namespace TelEngine;
namespace { // anonymous
// The factory
class CustomTableFactory : public UIFactory
{
public:
inline CustomTableFactory(const char* name = "CustomTableFactory")
: UIFactory(name)
{ m_types.append(new String("CustomTable")); }
virtual void* create(const String& type, const char* name, NamedList* params = 0);
};
// Utility class used to disable/enable a table sorting and widget update flag
class SafeWidget
{
public:
SafeWidget(QTableWidget* table)
: m_widget(table), m_table(0) {
if (m_widget)
m_widget->setUpdatesEnabled(false);
if (table && table->isSortingEnabled()) {
m_table = table;
m_table->setSortingEnabled(false);
}
}
~SafeWidget()
{ drop(); }
inline void drop() {
if (m_table)
m_table->setSortingEnabled(true);
if (m_widget)
m_widget->setUpdatesEnabled(true);
m_widget = 0;
m_table = 0;
}
private:
QWidget* m_widget;
QTableWidget* m_table;
};
static CustomTableFactory s_factory;
static inline const String& objListItem(ObjList* list, int index)
{
GenObject* gen = list ? (*list)[index] : 0;
return gen ? gen->toString() : String::empty();
}
/*
* CustomTable
*/
// Constructor for a custom table
CustomTable::CustomTable(const char *name, const NamedList& params, QWidget* parent)
: QtTable(name,parent),
m_rowHeight(0), m_horzHeader(true),
m_notifyItemChanged(false), m_notifySelChgOnRClick(true),
m_contextMenu(0), m_changing(false)
{
// Build properties
QtClient::buildProps(this,params["buildprops"]);
// Set horizontal header
QHeaderView* h = horizontalHeader();
if (h)
h->setHighlightSections(false);
ObjList* cols = params["hheader_columns"].split(',',false);
ObjList* title = params["hheader_columns_title"].split(',',true);
ObjList* check = params["hheader_columns_check"].split(',',false);
ObjList* size = params["hheader_columns_size"].split(',',true);
ObjList* resize = params["hheader_columns_resize"].split(',',true);
int n = cols->count();
setColumnCount(n);
for (int i = 0; i < n; i++) {
String id = objListItem(cols,i);
String text = objListItem(title,i);
if (!text)
text = id;
QTableWidgetItem* it = new QTableWidgetItem(QtClient::setUtf8(text));
id.toLower();
it->setData(ColumnId,QVariant(QtClient::setUtf8(id)));
if (check->find(id))
it->setData(ColumnItemCheckable,QVariant(true));
setHorizontalHeaderItem(i,it);
if (!h)
continue;
// Set column width
int w = objListItem(size,i).toInteger();
if (w > 0)
h->resizeSection(i,w);
// Set column resize mode
const String& resizeMode = objListItem(resize,i);
if (resizeMode == "fixed")
h->setResizeMode(i,QHeaderView::Fixed);
else if (resizeMode == "stretch")
h->setResizeMode(i,QHeaderView::Stretch);
else if (resizeMode == "contents")
h->setResizeMode(i,QHeaderView::ResizeToContents);
else
h->setResizeMode(i,QHeaderView::Interactive);
}
TelEngine::destruct(cols);
TelEngine::destruct(title);
TelEngine::destruct(check);
TelEngine::destruct(size);
TelEngine::destruct(resize);
// Init properties
m_saveProps << "_yate_col_widths";
m_saveProps << "_yate_sorting";
setSelectionMode(QAbstractItemView::SingleSelection);
setSelectionBehavior(QAbstractItemView::SelectRows);
setEditTriggers(QAbstractItemView::NoEditTriggers);
setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
// Connect signals
QtClient::connectObjects(this,SIGNAL(cellChanged(int,int)),this,SLOT(itemCellChanged(int,int)));
// Apply parameters
setParams(params);
}
CustomTable::~CustomTable()
{
}
bool CustomTable::setParams(const NamedList& params)
{
SafeWidget tbl(this);
QtUIWidget::setParams(params);
unsigned int n = params.length();
for (unsigned int i = 0; i < n; i++) {
NamedString* param = params.getParam(i);
if (!param)
continue;
if (param->name() == "filtervalue")
setFilter(*param);
else if (param->name() == "dynamiccellclicked")
setProperty("dynamicCellClicked",QVariant(QString(*param)));
else if (param->name() == "dynamicnoitemselchanged")
setProperty("dynamicNoItemSelChanged",QVariant(QString(*param)));
else if (param->name().startsWith("property:")) {
String prop = param->name().substr(9);
QWidget* target = this;
if (prop.startSkip("hheader:",false))
target = horizontalHeader();
if (target)
QtClient::setProperty(target,prop,*param);
}
else if (param->name() == "menu") {
// Re-build the context menu
if (m_contextMenu) {
QtClient::deleteLater(m_contextMenu);
m_contextMenu = 0;
}
NamedList* menu = static_cast<NamedList*>(param->getObject("NamedList"));
if (menu) {
// Get parent window receiving menu events
QtWindow* wnd = static_cast<QtWindow*>(window());
if (wnd)
m_contextMenu = QtClient::buildMenu(*menu,*menu,wnd,SLOT(action()),
SLOT(toggled(bool)),this);
}
}
else if (param->name() == "notifyselchgonrightclick")
m_notifySelChgOnRClick = param->toBoolean(m_notifySelChgOnRClick);
else if (param->name() == "filterby") {
setFilter();
m_filterBy.clear();
ObjList* list = param->split(',',false);
for (ObjList* o = list->skipNull(); o; o = o->skipNext()) {
String* s = static_cast<String*>(o->get());
m_filterBy.append(QtClient::setUtf8(s->toLower()));
}
TelEngine::destruct(list);
}
}
tbl.drop();
return true;
}
bool CustomTable::getOptions(NamedList& items)
{
int n = rowCount();
for (int i = 0; i < n; i++) {
String id;
if (getId(id,i) && id)
items.addParam(id,"");
}
return true;
}
bool CustomTable::addTableRow(const String& item, const NamedList* data, bool atStart)
{
DDebug(ClientDriver::self(),DebugAll,"CustomTable(%s)::addTableRow(%s,%p,%u)",
name().c_str(),item.c_str(),data,atStart);
SafeWidget tbl(this);
int row = atStart ? 0 : rowCount();
insertRow(row);
if (setRow(row,data,item))
return true;
removeRow(row);
return false;
}
// Add or set one or more table row(s). Screen update is locked while changing the table.
// Each data list element is a NamedPointer carrying a NamedList with item parameters.
// The name of an element is the item to update.
// Set element's value to boolean value 'true' to add a new item if not found
// or 'false' to set an existing one. Set it to empty string to delete the item
bool CustomTable::updateTableRows(const NamedList* data, bool atStart)
{
if (!data)
return true;
DDebug(ClientDriver::self(),DebugAll,"CustomTable(%s)::updateTableRows(%p,%u)",
name().c_str(),data,atStart);
// Remember selected item
bool ok = true;
SafeWidget tbl(this);
unsigned int n = data->length();
ObjList add;
// Delete and update rows
for (unsigned int i = 0; i < n; i++) {
if (Client::exiting())
break;
// Get item and the list of parameters
NamedString* ns = data->getParam(i);
if (!ns)
continue;
// Delete ?
if (ns->null()) {
int row = getRow(ns->name());
if (row >= 0)
removeRow(row);
else
ok = false;
continue;
}
// Set item or postpone add
int row = getRow(ns->name());
if (row >= 0)
setRow(row,YOBJECT(NamedList,ns));
else if (ns->toBoolean())
add.append(ns)->setDelete(false);
else
ok = false;
}
n = add.count();
if (n) {
int row = rowCount();
if (row < 0)
row = 0;
// Append if not requested to insert at start or table is empty
if (!(atStart && row))
setRowCount(row + n);
else {
for (unsigned int i = 0; i < n; i++)
insertRow(0);
}
for (ObjList* o = add.skipNull(); o; row++, o = o->skipNext()) {
NamedString* ns = static_cast<NamedString*>(o->get());
if (!setRow(row,YOBJECT(NamedList,ns),ns->name()))
ok = false;
}
}
return ok;
}
bool CustomTable::delTableRow(const String& item)
{
SafeWidget tbl(this);
int row = getRow(item);
DDebug(ClientDriver::self(),DebugAll,"CustomTable(%s)::delTableRow(%s) found=%d",
name().c_str(),item.c_str(),row);
if (row < 0)
return false;
removeRow(row);
return true;
}
bool CustomTable::setTableRow(const String& item, const NamedList* data)
{
SafeWidget tbl(this);
int row = getRow(item);
DDebug(ClientDriver::self(),DebugAll,"CustomTable(%s)::setTableRow(%s,%p) found=%d",
name().c_str(),item.c_str(),data,row);
if (row < 0)
return false;
return setRow(row,data);
}
bool CustomTable::getTableRow(const String& item, NamedList* data)
{
int row = getRow(item);
DDebug(ClientDriver::self(),DebugAll,"CustomTable(%s)::getTableRow(%s,%p) found=%d",
name().c_str(),item.c_str(),data,row);
if (row < 0)
return false;
if (!data)
return true;
int n = columnCount();
for (int i = 1; i < n; i++) {
String name;
bool checkable = false;
QTableWidgetItem* h = getColumnId(name,checkable,i);
if (!(h && name))
continue;
QTableWidgetItem* it = QTableWidget::item(row,i);
if (!it)
continue;
NamedString* ns = new NamedString(name);
QtClient::getUtf8(*ns,it->text());
data->setParam(ns);
if (checkable)
data->setParam("check:" + name,String::boolText(it->checkState() == Qt::Checked));
}
return true;
}
bool CustomTable::clearTable()
{
setRowCount(0);
return true;
}
// Set the selected entry
bool CustomTable::setSelect(const String& item)
{
if (!item)
return true;
int row = getRow(item);
DDebug(ClientDriver::self(),DebugAll,"CustomTable(%s)::setSelect(%s) found=%d",
name().c_str(),item.c_str(),row);
if (row < 0)
return false;
setCurrentCell(row,1);
return true;
}
bool CustomTable::getSelect(String& item)
{
int row = currentRow();
QTableWidgetItem* it = 0;
if (row >= 0) {
it = QTableWidget::item(row,0);
if (it)
QtClient::getUtf8(item,it->text());
}
DDebug(ClientDriver::self(),DebugAll,"CustomTable(%s)::getSelect() found=(%d,%s)",
name().c_str(),row,item.c_str());
return it != 0;
}
// Find a table row by its item id
int CustomTable::getRow(const String& item)
{
const QString tmp = QtClient::setUtf8(item);
for (int i = 0; i < rowCount(); i++) {
QTableWidgetItem* it = this->item(i,0);
if (it && it->text() == tmp)
return i;
}
return -1;
}
// Find a table row id by its row index
bool CustomTable::getId(String& item, int row)
{
QTableWidgetItem* it = this->item(row,0);
if (it)
QtClient::getUtf8(item,it->text());
return it != 0;
}
// Find a column by its label. Return -1 if not found
QTableWidgetItem* CustomTable::getColumnId(String& id, bool& checkable, int col)
{
QTableWidgetItem* it = horizontalHeaderItem(col);
if (!it)
return 0;
QVariant var = it->data(ColumnId);
if (var.type() == QVariant::String)
QtClient::getUtf8(id,var.toString());
else {
QtClient::getUtf8(id,it->text());
id.toLower();
}
var = it->data(ColumnItemCheckable);
checkable = var.toBool();
return it;
}
// Find a column by its label. Return -1 if not found
int CustomTable::getColumn(const QString& name, bool hidden, bool caseInsensitive)
{
static QString ht("hidden:");
QString what = name;
if (hidden)
what.insert(0,ht);
Qt::CaseSensitivity cs = caseInsensitive ? Qt::CaseInsensitive : Qt::CaseSensitive;
int n = columnCount();
for (int i = 0; i < n; i++) {
QTableWidgetItem* it = horizontalHeaderItem(i);
if (!it)
continue;
QVariant var = it->data(ColumnId);
if (var.type() == QVariant::String) {
if (0 == var.toString().compare(what,cs))
return i;
}
else if (0 == it->text().compare(what,cs))
return i;
}
return -1;
}
// (de)activate enter key press action
void CustomTable::setEnterPressNotify(bool value)
{
QAction* act = qFindChild<QAction*>(this,m_enterKeyActionName);
if (act) {
if (!value) {
QWidget::removeAction(act);
QtClient::deleteLater(act);
}
return;
}
if (!value)
return;
act = new QAction("",this);
act->setObjectName(m_enterKeyActionName);
act->setShortcut(QKeySequence(Qt::Key_Return));
act->setShortcutContext(Qt::WidgetShortcut);
act->setProperty("_yate_autoconnect",QVariant(false));
QWidget::addAction(act);
QtClient::connectObjects(act,SIGNAL(triggered()),this,SLOT(actionTriggered()));
}
// Retrieve table columns widths
QString CustomTable::getColWidths()
{
String widths;
int n = columnCount();
for (int i = 0; i < n; i++)
widths.append(String(columnWidth(i)),",",true);
return QtClient::setUtf8(widths);
}
// Set the table columns widths string
void CustomTable::setColWidths(QString value)
{
QStringList list = value.split(',');
for (int i = 0; i < list.size(); i++) {
bool ok = true;
int w = list[i].toInt(&ok);
if (ok && w >= 0)
setColumnWidth(i,w);
}
}
// Retrieve table sorting
QString CustomTable::getSorting()
{
String sorting;
if (isSortingEnabled()) {
QHeaderView* h = horizontalHeader();
int col = h ? h->sortIndicatorSection() : -1;
if (col >= 0)
sorting << col << "," <<
String::boolText(Qt::AscendingOrder == h->sortIndicatorOrder());
}
return QtClient::setUtf8(sorting);
}
// Set the table sorting
void CustomTable::setSorting(QString value)
{
QStringList list = value.split(',');
if (list.size() < 2)
return;
bool ok = true;
int col = list[0].toInt(&ok);
if (ok && col >= 0 && col < columnCount()) {
String tmp;
QtClient::getUtf8(tmp,list[1]);
sortItems(col,tmp.toBoolean(true) ? Qt::AscendingOrder : Qt::DescendingOrder);
}
}
// Setup a row
bool CustomTable::setRow(int row, const NamedList* data, const String& item)
{
DDebug(ClientDriver::self(),DebugAll,"CustomTable(%s)::setRow(%d,%p,%s)",
name().c_str(),row,data,item.c_str());
m_changing = true;
int n = columnCount();
// First init
if (item) {
// Set row id
setItem(row,0,new QTableWidgetItem(QtClient::setUtf8(item)));
// Set row height
if (m_rowHeight > 0)
QTableWidget::setRowHeight(row,m_rowHeight);
// Set checkable columns
for (int i = 1; i < n; i++) {
String name;
bool checkable = false;
getColumnId(name,checkable,i);
if (!checkable)
continue;
QTableWidgetItem* it = QTableWidget::item(row,i);
if (!it) {
it = new QTableWidgetItem;
setItem(row,i,it);
}
it->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsSelectable | Qt::ItemIsEnabled);
it->setCheckState(Qt::Unchecked);
}
}
if (!data) {