diff --git a/linphone-desktop/resources.qrc b/linphone-desktop/resources.qrc
index c11aa5908..07c9622f4 100644
--- a/linphone-desktop/resources.qrc
+++ b/linphone-desktop/resources.qrc
@@ -187,6 +187,7 @@
ui/modules/Common/Form/ComboBox.qml
ui/modules/Common/Form/DroppableTextArea.qml
ui/modules/Common/Form/Fields/NumericField.qml
+ ui/modules/Common/Form/Fields/PortField.qml
ui/modules/Common/Form/Fields/TextAreaField.qml
ui/modules/Common/Form/Fields/TextField.qml
ui/modules/Common/Form/+linux/SearchBox.qml
@@ -301,6 +302,7 @@
ui/modules/Linphone/Timeline.qml
ui/scripts/LinphoneUtils/linphone-utils.js
ui/scripts/LinphoneUtils/qmldir
+ ui/scripts/Utils/port-tools.js
ui/scripts/Utils/qmldir
ui/scripts/Utils/uri-tools.js
ui/scripts/Utils/utils.js
diff --git a/linphone-desktop/src/components/settings/SettingsModel.cpp b/linphone-desktop/src/components/settings/SettingsModel.cpp
index 616db664a..f357bdb9d 100644
--- a/linphone-desktop/src/components/settings/SettingsModel.cpp
+++ b/linphone-desktop/src/components/settings/SettingsModel.cpp
@@ -42,22 +42,23 @@ SettingsModel::SettingsModel (QObject *parent) : QObject(parent) {
// Network.
// =============================================================================
-bool SettingsModel::getUseRfc2833ForDtmfs () const {
- return CoreManager::getInstance()->getCore()->getUseRfc2833ForDtmf();
+QList SettingsModel::getVideoPortRange () const {
+ int a, b;
+ CoreManager::getInstance()->getCore()->getVideoPortRange(a, b);
+ return QList() << a << b;
}
-void SettingsModel::setUseRfc2833ForDtmfs (bool status) {
+void SettingsModel::setVideoPortRange (const QList &range) {
shared_ptr core = CoreManager::getInstance()->getCore();
+ int a = range[0];
+ int b = range[1];
- if (status) {
- core->setUseInfoForDtmf(false);
- core->setUseRfc2833ForDtmf(true);
- } else {
- core->setUseRfc2833ForDtmf(false);
- core->setUseInfoForDtmf(true);
- }
+ if (b == -1)
+ core->setVideoPort(a);
+ else
+ core->setVideoPortRange(a, b);
- emit dtmfsProtocolChanged();
+ emit videoPortRangeChanged(a, b);
}
// -----------------------------------------------------------------------------
@@ -82,6 +83,26 @@ void SettingsModel::setUseSipInfoForDtmfs (bool status) {
// -----------------------------------------------------------------------------
+bool SettingsModel::getUseRfc2833ForDtmfs () const {
+ return CoreManager::getInstance()->getCore()->getUseRfc2833ForDtmf();
+}
+
+void SettingsModel::setUseRfc2833ForDtmfs (bool status) {
+ shared_ptr core = CoreManager::getInstance()->getCore();
+
+ if (status) {
+ core->setUseInfoForDtmf(false);
+ core->setUseRfc2833ForDtmf(true);
+ } else {
+ core->setUseRfc2833ForDtmf(false);
+ core->setUseInfoForDtmf(true);
+ }
+
+ emit dtmfsProtocolChanged();
+}
+
+// -----------------------------------------------------------------------------
+
bool SettingsModel::getIpv6Enabled () const {
return CoreManager::getInstance()->getCore()->ipv6Enabled();
}
diff --git a/linphone-desktop/src/components/settings/SettingsModel.hpp b/linphone-desktop/src/components/settings/SettingsModel.hpp
index 89247a279..d3ccfa018 100644
--- a/linphone-desktop/src/components/settings/SettingsModel.hpp
+++ b/linphone-desktop/src/components/settings/SettingsModel.hpp
@@ -31,6 +31,8 @@
class SettingsModel : public QObject {
Q_OBJECT;
+ Q_PROPERTY(QList videoPortRange READ getVideoPortRange WRITE setVideoPortRange NOTIFY videoPortRangeChanged);
+
Q_PROPERTY(bool useSipInfoForDtmfs READ getUseSipInfoForDtmfs WRITE setUseSipInfoForDtmfs NOTIFY dtmfsProtocolChanged);
Q_PROPERTY(bool useRfc2833ForDtmfs READ getUseRfc2833ForDtmfs WRITE setUseRfc2833ForDtmfs NOTIFY dtmfsProtocolChanged);
@@ -47,6 +49,9 @@ public:
// Network. ------------------------------------------------------------------
+ QList getVideoPortRange () const;
+ void setVideoPortRange (const QList &range);
+
bool getUseSipInfoForDtmfs () const;
void setUseSipInfoForDtmfs (bool status);
@@ -75,6 +80,8 @@ public:
static const std::string UI_SECTION;
signals:
+ void videoPortRangeChanged (int a, int b);
+
void dtmfsProtocolChanged ();
void ipv6EnabledChanged (bool status);
diff --git a/linphone-desktop/ui/modules/Common/Form/Fields/PortField.qml b/linphone-desktop/ui/modules/Common/Form/Fields/PortField.qml
new file mode 100644
index 000000000..32711dbde
--- /dev/null
+++ b/linphone-desktop/ui/modules/Common/Form/Fields/PortField.qml
@@ -0,0 +1,76 @@
+import QtQuick 2.7
+
+import Utils 1.0
+
+// =============================================================================
+
+Item {
+ id: wrapper
+
+ // ---------------------------------------------------------------------------
+
+ property string text
+ property bool supportsRange: false
+
+ // ---------------------------------------------------------------------------
+
+ signal editingFinished (int portA, int portB)
+
+ // ---------------------------------------------------------------------------
+
+ function _extractPorts (text) {
+ var portA = +text.split(':')[0]
+ var portB = (function () {
+ var port = text.split(':')[1]
+ return port && port.length > 0 ? +port : -1
+ })()
+
+ if (portB < 0 || portA === portB) {
+ return [ portA, -1 ]
+ }
+
+ if (portA < portB) {
+ return [ portA, portB ]
+ }
+
+ return [ portB, portA ]
+ }
+
+ function _computeText (range) {
+ return range[1] < 0
+ ? range[0]
+ : range[0] + ':' + range[1]
+ }
+
+ // ---------------------------------------------------------------------------
+
+ implicitWidth: textField.width
+ implicitHeight: textField.height
+
+ onTextChanged: textField.text = _computeText(_extractPorts(text))
+
+ // ---------------------------------------------------------------------------
+
+ TextField {
+ id: textField
+
+ property bool locked: false
+
+ validator: RegExpValidator {
+ regExp: wrapper.supportsRange
+ ? Utils.PORT_RANGE_REGEX
+ : Utils.PORT_REGEX
+ }
+
+ // Workaround to supports empty string.
+ Keys.onReturnPressed: editingFinished()
+ onActiveFocusChanged: !activeFocus && !text.length && editingFinished()
+
+ onEditingFinished: {
+ var range = _extractPorts(textField.text)
+
+ wrapper.text = textField.text = _computeText(range)
+ wrapper.editingFinished(range[0], range[1])
+ }
+ }
+}
diff --git a/linphone-desktop/ui/modules/Common/qmldir b/linphone-desktop/ui/modules/Common/qmldir
index e291216af..945b20c42 100644
--- a/linphone-desktop/ui/modules/Common/qmldir
+++ b/linphone-desktop/ui/modules/Common/qmldir
@@ -34,6 +34,7 @@ TextButtonA 1.0 Form/Buttons/TextButtonA.qml
TextButtonB 1.0 Form/Buttons/TextButtonB.qml
NumericField 1.0 Form/Fields/NumericField.qml
+PortField 1.0 Form/Fields/PortField.qml
TextAreaField 1.0 Form/Fields/TextAreaField.qml
TextField 1.0 Form/Fields/TextField.qml
diff --git a/linphone-desktop/ui/scripts/Utils/port-tools.js b/linphone-desktop/ui/scripts/Utils/port-tools.js
new file mode 100644
index 000000000..ed7019a5a
--- /dev/null
+++ b/linphone-desktop/ui/scripts/Utils/port-tools.js
@@ -0,0 +1,15 @@
+// =============================================================================
+// Library to deal with Ports.
+// =============================================================================
+
+.pragma library
+
+// -----------------------------------------------------------------------------
+
+var PORT = '([0-9]{1,4}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])'
+var PORT_RANGE = PORT + '(?::' + PORT + ')?'
+
+// -----------------------------------------------------------------------------
+
+var PORT_REGEX = new RegExp('^' + PORT + '$')
+var PORT_RANGE_REGEX = new RegExp('^' + PORT_RANGE + '$')
diff --git a/linphone-desktop/ui/scripts/Utils/utils.js b/linphone-desktop/ui/scripts/Utils/utils.js
index d79a05e60..0aae4811b 100644
--- a/linphone-desktop/ui/scripts/Utils/utils.js
+++ b/linphone-desktop/ui/scripts/Utils/utils.js
@@ -6,8 +6,16 @@
.import QtQuick 2.0 as QtQuick
+.import 'port-tools.js' as PortTools
.import 'uri-tools.js' as UriTools
+// =============================================================================
+// Constants.
+// =============================================================================
+
+var PORT_REGEX = PortTools.PORT_REGEX
+var PORT_RANGE_REGEX = PortTools.PORT_RANGE_REGEX
+
// =============================================================================
// QML helpers.
// =============================================================================
diff --git a/linphone-desktop/ui/views/App/Settings/SettingsNetwork.qml b/linphone-desktop/ui/views/App/Settings/SettingsNetwork.qml
index 4f3f1e230..a15857cb9 100644
--- a/linphone-desktop/ui/views/App/Settings/SettingsNetwork.qml
+++ b/linphone-desktop/ui/views/App/Settings/SettingsNetwork.qml
@@ -12,41 +12,6 @@ TabContainer {
spacing: SettingsWindowStyle.forms.spacing
width: parent.width
- // -------------------------------------------------------------------------
- // Transport.
- // -------------------------------------------------------------------------
-
- Form {
- title: qsTr('transportTitle')
- width: parent.width
-
- FormLine {
- FormGroup {
- label: qsTr('sendDtmfsLabel')
-
- ExclusiveButtons {
- selectedButton: Number(!SettingsModel.useSipInfoForDtmfs)
- texts: [
- 'SIP INFO',
- 'RFC 2833'
- ]
-
- onClicked: SettingsModel.useSipInfoForDtmfs = !button
- }
- }
-
- FormGroup {
- label: qsTr('allowIpV6Label')
-
- Switch {
- checked: SettingsModel.ipv6Enabled
-
- onClicked: SettingsModel.ipv6Enabled = !checked
- }
- }
- }
- }
-
// -------------------------------------------------------------------------
// Network protocol and ports.
// -------------------------------------------------------------------------
@@ -73,10 +38,12 @@ TabContainer {
FormGroup {
label: qsTr('sipUdpPortLabel')
- NumericField {
- minValue: 0
- maxValue: 65535
- readOnly: randomSipUdpPort.checked || !enableSipUdpPort.checked
+ PortField {
+ //readOnly: randomSipUdpPort.checked || !enableSipUdpPort.checked
+ supportsRange: true
+ text: SettingsModel.videoPortRange.join(':')
+
+ onEditingFinished: SettingsModel.videoPortRange = [ portA, portB ]
}
}
@@ -184,6 +151,41 @@ TabContainer {
}
}
+ // -------------------------------------------------------------------------
+ // Transport.
+ // -------------------------------------------------------------------------
+
+ Form {
+ title: qsTr('transportTitle')
+ width: parent.width
+
+ FormLine {
+ FormGroup {
+ label: qsTr('sendDtmfsLabel')
+
+ ExclusiveButtons {
+ selectedButton: Number(!SettingsModel.useSipInfoForDtmfs)
+ texts: [
+ 'SIP INFO',
+ 'RFC 2833'
+ ]
+
+ onClicked: SettingsModel.useSipInfoForDtmfs = !button
+ }
+ }
+
+ FormGroup {
+ label: qsTr('allowIpV6Label')
+
+ Switch {
+ checked: SettingsModel.ipv6Enabled
+
+ onClicked: SettingsModel.ipv6Enabled = !checked
+ }
+ }
+ }
+ }
+
// -------------------------------------------------------------------------
// DSCP fields.
// -------------------------------------------------------------------------