Add log function to settings
authorzhou_xin <zhou_xin@dl.cn.nexty-ele.com>
Sat, 2 Mar 2019 05:41:21 +0000 (13:41 +0800)
committerzhou_xin <zhou_xin@dl.cn.nexty-ele.com>
Sat, 2 Mar 2019 05:41:21 +0000 (13:41 +0800)
29 files changed:
app/Settings.qml
app/app.pro
app/logfile/AudioLog.qml [new file with mode: 0644]
app/logfile/Bar.qml [new file with mode: 0644]
app/logfile/CANLog.qml [new file with mode: 0644]
app/logfile/LogFile.qml [new file with mode: 0644]
app/logfile/LogPlay.qml [new file with mode: 0644]
app/logfile/LogSave.qml [new file with mode: 0644]
app/logfile/TouchLog.qml [new file with mode: 0644]
app/logfile/TouchLogPlay.qml [new file with mode: 0644]
app/logfile/VideoLog.qml [new file with mode: 0644]
app/logfile/images/HMI_Settings_Button_Cancel.svg [new file with mode: 0644]
app/logfile/images/HMI_Settings_Button_Ok.svg [new file with mode: 0644]
app/logfile/images/HMI_Settings_LogFile.svg [new file with mode: 0644]
app/logfile/images/Keyboard_Arrow.svg [new file with mode: 0644]
app/logfile/images/Keyboard_Back.svg [new file with mode: 0644]
app/logfile/images/camerainfo_bg.svg [new file with mode: 0644]
app/logfile/keyboard/AbstractKeyboard.qml [new file with mode: 0644]
app/logfile/keyboard/Key.qml [new file with mode: 0644]
app/logfile/keyboard/Keyboard.qml [new file with mode: 0644]
app/logfile/keyboard/Numbers.qml [new file with mode: 0644]
app/logfile/logfile.qrc [new file with mode: 0644]
app/logfile/logplay.cpp [new file with mode: 0644]
app/logfile/logplay.h [new file with mode: 0644]
app/logfile/logsave.cpp [new file with mode: 0644]
app/logfile/logsave.h [new file with mode: 0644]
app/logfile/touchlogplay.cpp [new file with mode: 0644]
app/logfile/touchlogplay.h [new file with mode: 0644]
app/main.cpp

index bfcec3a..2040345 100644 (file)
@@ -22,6 +22,7 @@ import 'datetime'
 import 'bluetooth'
 import 'wifi'
 import 'version'
+import 'logfile'
 
 ApplicationWindow {
     id: root
@@ -69,6 +70,8 @@ ApplicationWindow {
 
         Wifi {}
 
+        LogFile {}
+
         Version {}
     }
 }
index 566d2b6..c7278b4 100644 (file)
@@ -1,7 +1,15 @@
 TARGET = settings
 QT = quickcontrols2 websockets
 
-SOURCES = main.cpp
+HEADERS += \
+    logfile/logsave.h \
+    logfile/logplay.h \
+    logfile/touchlogplay.h
+
+SOURCES = main.cpp \
+    logfile/logsave.cpp \
+    logfile/logplay.cpp \
+    logfile/touchlogplay.cpp
 
 CONFIG += link_pkgconfig
 PKGCONFIG += libhomescreen qlibwindowmanager qtappfw
@@ -12,7 +20,8 @@ RESOURCES += \
     datetime/datetime.qrc \
     wifi/wifi.qrc \
     bluetooth/bluetooth.qrc \
-    version/version.qrc
+    version/version.qrc \
+    logfile/logfile.qrc
 
 
 include(app.pri)
diff --git a/app/logfile/AudioLog.qml b/app/logfile/AudioLog.qml
new file mode 100644 (file)
index 0000000..da2fd27
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import QtQuick 2.6
+import QtQuick.Layouts 1.1
+import QtQuick.Controls 2.0
+import '..'
+
+RowLayout {
+    id: audiolog
+
+    property int currentsps: 0
+    property int part1fontsize: 30
+    property int part2fontsize: 30
+    property int partheight: 50
+    property int part1width: 250
+    property int part2width: 600
+
+    Item {
+        implicitWidth: part1width
+        implicitHeight: partheight
+        Label {
+            anchors.right: parent.right
+            anchors.bottom: parent.bottom
+            font.pixelSize: part1fontsize
+            text: 'SPS  :  '
+        }
+    }
+
+    TextField {
+        id: textfield
+        implicitWidth: part2width
+        implicitHeight: partheight
+        validator: IntValidator{bottom: 4000; top: 192000;}
+        color: 'white'
+        font.pixelSize: part2fontsize
+        verticalAlignment: TextInput.AlignBottom
+        Label {
+            x: parent.width - width
+            y: parent.height - height
+            text: '(4000~192000)'
+            color: 'gray'
+            font.pixelSize: 20
+        }
+        onTextChanged: {
+            if(text == '0') {
+                text = ''
+            }
+            if(text.length > 0) {
+                currentsps = text
+            }
+            else {
+                currentsps = 0
+            }
+        }
+        onFocusChanged: {
+            root.updateKeyBoard()
+            if(!focus && text < 4000) {
+                text = 4000
+            }
+        }
+        Component.onCompleted: {
+            root.addTarget(textfield)
+        }
+    }
+}
diff --git a/app/logfile/Bar.qml b/app/logfile/Bar.qml
new file mode 100644 (file)
index 0000000..444c107
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import QtQuick 2.6
+import QtQuick.Layouts 1.3
+import QtQuick.Controls 2.0
+import '..'
+
+TabBar {
+    id: root
+    property int tabbtnwidth: 460
+    property int tabbtnheight: 51
+    anchors.left: parent.left
+    anchors.right: parent.right
+    anchors.margins: 80
+    background.opacity: 0
+    Repeater {
+        id: tabs
+        model: ['Log Save', 'Log Play', 'Touch Log Play']
+        delegate: TabButton {
+            implicitWidth: tabbtnwidth
+            implicitHeight: tabbtnheight
+            contentItem: Text {
+                text: model.modelData
+                font.family: 'Roboto'
+                font.pixelSize: 30
+                opacity: enabled ? 1.0 : 0.3
+                color: parent.down ? "#17a81a" : "white"
+                horizontalAlignment: Text.AlignHCenter
+                verticalAlignment: Text.AlignVCenter
+                elide: Text.ElideRight
+            }
+            background: Image {
+                anchors.fill: parent
+                transform: parent.down ? opacity = 1.0 : opacity = 0.75
+            }
+        }
+    }
+    Component.onCompleted: {
+        setBgImg()
+    }
+
+    onCurrentIndexChanged: {
+        setBgImg()
+    }
+
+    function setBgImg() {
+        for(var i = 0; i < tabs.count && i < root.count; i++) {
+            if(i == root.currentIndex) {
+                tabs.itemAt(i).background.source = './images/HMI_Settings_Button_Ok.svg';
+            }
+            else {
+                tabs.itemAt(i).background.source = './images/HMI_Settings_Button_Cancel.svg';
+            }
+        }
+    }
+}
diff --git a/app/logfile/CANLog.qml b/app/logfile/CANLog.qml
new file mode 100644 (file)
index 0000000..a3e26a1
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import QtQuick 2.6
+import QtQuick.Layouts 1.1
+import QtQuick.Controls 2.0
+import '..'
+
+ColumnLayout {
+    anchors.left: parent.left
+    anchors.leftMargin: 100
+    Label {
+        text: 'There is no property which needs to be set.'
+        font.pixelSize: 30
+    }
+}
diff --git a/app/logfile/LogFile.qml b/app/logfile/LogFile.qml
new file mode 100644 (file)
index 0000000..fbf2eb9
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import QtQuick 2.6
+import QtQuick.Layouts 1.3
+import QtQuick.Controls 2.0
+import '..'
+import './keyboard'
+
+SettingPage {
+    id: root
+    icon: '/logfile/images/HMI_Settings_LogFile.svg'
+    title: 'LogFile'
+    property string trippath: ''
+    property string rootpath: ''
+    property var targets: new Array()
+
+    Bar {
+        id: tabbar
+        onCurrentIndexChanged: {
+            keyboard.visible = false
+        }
+    }
+    StackLayout {
+        id: pages
+        anchors.left: tabbar.left
+        anchors.right: tabbar.right
+        anchors.top: tabbar.bottom
+        currentIndex: tabbar.currentIndex
+        LogSave { id: logsave }
+        LogPlay { id: logplay }
+        TouchLogPlay { id: touchlogplay }
+    }
+
+    Keyboard {
+        id: keyboard
+        anchors.bottom: parent.bottom
+        anchors.left: parent.left
+        anchors.right: parent.right
+        active: numbers
+        onVisibleChanged: {
+            var children = pages.children
+            for(var child in children) {
+                if(children[child].visible) {
+                    children[child].resetPosition()
+                    break;
+                }
+            }
+        }
+        Numbers {
+            id: numbers
+            anchors.left: parent.left
+            anchors.right: parent.right
+            anchors.leftMargin: parent.height / 2
+            anchors.rightMargin: parent.height / 2
+            target: parent.target
+            onHide: {
+                keyboard.visible = false
+                target.focus = false
+            }
+            onNext: {
+                var nexttarget
+                for(var i = 0; i < targets.length; i++) {
+                    if(targets[i] === target) {
+                        for(var j = i, k = 0; k < targets.length; k++) {
+                            if(j === targets.length-1) {
+                                j = 0;
+                            }
+                            else {
+                                j++;
+                            }
+                            if(targets[j].visible) {
+                                target.focus = false
+                                nexttarget = targets[j]
+                                nexttarget.focus = true
+                                break;
+                            }
+                        }
+                        break;
+                    }
+                }
+            }
+        }
+    }
+
+    onVisibleChanged: {
+        if(!visible) {
+            keyboard.visible = false
+        }
+    }
+
+    function updateKeyBoard() {
+        var textfield = 0
+        for(var i = 0; i < targets.length; i++) {
+            if(targets[i].focus) {
+                textfield = targets[i]
+            }
+        }
+
+        if(textfield === 0) {
+            keyboard.visible = false
+            return
+        }
+        else {
+            keyboard.target = textfield
+            keyboard.visible = true
+        }
+
+        var implicity = 0.0
+        for(var itext = textfield; itext !== pages; itext = itext.parent) {
+            implicity += itext.y
+        }
+        implicity += itext.y
+
+        var keyboardy = implicity + textfield.height
+        if(keyboard.y < keyboardy) {
+            var children = pages.children
+            for(var child in children) {
+                if(children[child].visible) {
+                    children[child].adjustPosition(keyboardy - keyboard.y)
+                    break;
+                }
+            }
+        }
+    }
+
+    function addTarget(target) {
+        targets.push(target)
+    }
+}
diff --git a/app/logfile/LogPlay.qml b/app/logfile/LogPlay.qml
new file mode 100644 (file)
index 0000000..dbe5555
--- /dev/null
@@ -0,0 +1,355 @@
+/*
+ * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import QtQuick 2.6
+import QtQuick.Layouts 1.1
+import QtQuick.Controls 2.0
+import LogPlayImpl 1.0
+import '..'
+
+ColumnLayout {
+    property int blankheight : 50
+    property bool playing: false
+
+    property var timelist : ''
+    property var stime : ['1970', '01', '01', '00', '00', '00']
+    property var etime : ['1970', '01', '01', '00', '00', '00']
+    property var portslist : ['None']
+
+    anchors.left: parent.left
+    anchors.right: parent.right
+
+    Item { height:blankheight }
+
+    RowLayout{
+        anchors.left: parent.left
+        anchors.right: parent.right
+        Label { text: 'CAN Log files: ' ; color: '#59FF7F'}
+        RowLayout{
+            anchors.right: parent.right
+            Label { text: 'Port : ' }
+            ComboBox {
+                id: ports
+                implicitWidth: 220
+                font.family: 'Roboto'
+                font.pixelSize: 30
+                model: portslist
+                contentItem: Text {
+                    text: ports.displayText
+                    font: ports.font
+                    color: ports.pressed ? "#17a81a" : "white"
+                    horizontalAlignment: Text.AlignLeft
+                    verticalAlignment: Text.AlignVCenter
+                    elide: Text.ElideRight
+                }
+                indicator: Canvas {
+                    id: canvas
+                    x: ports.width - width - ports.rightPadding
+                    y: ports.topPadding + (ports.availableHeight - height) / 2
+                    width: 20
+                    height: 12
+                    contextType: "2d"
+
+                    Connections {
+                        target: ports
+                        onPressedChanged: canvas.requestPaint()
+                    }
+
+                    onPaint: {
+                        context.reset();
+                        context.moveTo(0, 0);
+                        context.lineTo(width, 0);
+                        context.lineTo(width / 2, height);
+                        context.closePath();
+                        context.fillStyle = ports.pressed ? "#17a81a" : "white";
+                        context.fill();
+                    }
+                }
+                popup: Popup {
+                    id: portspopup
+                    y: ports.height - 1
+                    implicitWidth: ports.width
+                    implicitHeight: listview.contentHeight
+                    padding: 0
+
+                    contentItem: ListView {
+                        id: listview
+                        clip: true
+                        model: portspopup.visible ? ports.delegateModel : null
+                        currentIndex: ports.highlightedIndex
+                        ScrollIndicator.vertical: ScrollIndicator { }
+                    }
+
+                    background: Image {
+                        source:'./images/HMI_Settings_Button_Cancel.svg'
+                    }
+                }
+                delegate: ItemDelegate {
+                    id: popupdelegate
+                    width: ports.width
+                    contentItem: Item {
+                        implicitHeight: 30
+                        Text {
+                            text: modelData
+                            color: popupdelegate.pressed || highlighted ? "#21be2b" : "white"
+                            font: ports.font
+                            elide: Text.ElideRight
+                            verticalAlignment: Text.AlignVCenter
+                        }
+                    }
+
+                    highlighted: ports.highlightedIndex == index
+                }
+
+                background: Image {
+                    source:'./images/HMI_Settings_Button_Cancel.svg'
+                }
+                onCurrentTextChanged: {
+                    if(currentText != 'None') {
+                        timelist = logplayimpl.getCanLogTime(currentText)
+                    }
+                }
+                onModelChanged: {
+                    if(currentText == '' || currentText == 'None') {
+                        enabled = false
+                    }
+                    else {
+                        enabled = true
+                    }
+                }
+            }
+        }
+    }
+    Item { height:blankheight/3 }
+    Image { source: '../images/HMI_Settings_DividingLine.svg' }
+    Item { height:blankheight/3 }
+    ListView {
+        id: loglist
+        property int impheight: 0
+        property int listitemheight : 50
+        property int listmaxheight : 600
+
+        anchors.left: parent.left
+        anchors.right: parent.right
+        anchors.margins: 20
+        implicitHeight: 0
+        clip: true
+        model:logplayimpl
+        delegate: MouseArea {
+            height: loglist.listitemheight
+            width: ListView.view.width
+            Label {
+                anchors.right: parent.right
+                anchors.bottom: parent.bottom
+                visible: model.children > 0 ? true : false
+                text: '' + model.children
+                color: 'gray'
+                font.pixelSize: 30
+            }
+            Image {
+                source: '../images/HMI_Settings_DividingLine.svg'
+                anchors.horizontalCenter: parent.horizontalCenter
+                anchors.top: parent.top
+                visible: model.index > 0
+            }
+            Image {
+                visible: loglist.currentIndex === model.index ? true : false
+                anchors.fill: parent
+                source:'./images/HMI_Settings_Button_Cancel.svg'
+            }
+            Label {
+                anchors.left: parent.left
+                anchors.bottom: parent.bottom
+                anchors.margins: 5
+                text: model.folder ? model.name : ' > ' + model.name
+                color: model.folder ? 'gray' : (loglist.currentIndex === model.index ? 'orange' : 'white')
+                font.pixelSize: 30
+            }
+            onClicked: {
+                if(!model.folder) {
+                    loglist.currentIndex = model.index
+                }
+            }
+        }
+        onCountChanged: {
+            impheight = (count * listitemheight) > listmaxheight ? listmaxheight : (count * listitemheight)
+            implicitHeight = impheight
+        }
+
+        Component.onCompleted: {
+            currentIndex = -1
+        }
+        onCurrentIndexChanged: {
+            model.setLogFileIndex(currentIndex)
+            portslist = model.getPortsList()
+            if(portslist.length == 0) {
+                portslist = ['None']
+            }
+            timelist = model.getCanLogTime(ports.currentText)
+        }
+    }
+    Item { height:blankheight/3 }
+    Image { source: '../images/HMI_Settings_DividingLine.svg' }
+    Item { height:blankheight/3 }
+    Repeater {
+        id: logtime
+        model: ['Start Time : ', 'End Time : ']
+        delegate: RowLayout {
+            property var curidx: model.index
+            Item {
+                implicitHeight: 50
+                implicitWidth: 250
+                Label {
+                    anchors.right: parent.right
+                    anchors.bottom: parent.bottom
+                    text: model.modelData
+                }
+            }
+            Repeater{
+                id: datetime
+                property list<IntValidator> range: [
+                    IntValidator{bottom: 0; top: 23;},
+                    IntValidator{bottom: 0; top: 59;},
+                    IntValidator{bottom: 0; top: 59;}
+                ]
+                model: 6
+                RowLayout {
+                    implicitHeight: 50
+                    implicitWidth: 120
+                    Label {
+                        anchors.bottom: parent.bottom
+                        visible: model.index > 0 ? true : false
+                        text: model.index === 3 ? '   ' : model.index > 3 ? ':' : '/'
+                        color: model.index < 3 ? 'gray' : 'white'
+                        font.pixelSize: 30
+                    }
+                    TextField {
+                        implicitWidth: model.index > 0 ? 60 : 90
+                        width: model.index > 0 ? 60 : 90
+                        text: (curidx*datetime.count + model.index) >= timelist.length ? '-' : timelist[(curidx*datetime.count + model.index)]
+                        color: model.index > 2 ? 'white' : 'gray'
+                        enabled: false
+                        font.pixelSize: 30
+                        horizontalAlignment: TextInput.AlignHCenter
+                        verticalAlignment: TextInput.AlignBottom
+                        onTextChanged: {
+                            if(model.index > 2 && text !== '/') {
+                                enabled = true
+                                if(text.length > 2) {
+                                    text = text.substring(text.length-2, text.length)
+                                }
+                            }
+                            else {
+                                enabled = false
+                            }
+                            if(curidx == 0 ) {
+                                if(model.index < stime.length) {
+                                    stime[model.index] = text;
+                                }
+                            }
+                            else {
+                                if(model.index < stime.length) {
+                                    etime[model.index] = text;
+                                }
+                            }
+                        }
+                        onFocusChanged: {
+                            root.updateKeyBoard()
+                            if(!focus) {
+                                if(text.length === 0) {
+                                    text = '00'
+                                }
+                                else if(text.length === 1 && text !== '/') {
+                                    text = '0' + text
+                                }
+                            }
+                        }
+                    }
+                }
+                Component.onCompleted: {
+                    for(var i = 3, j = 0; i < count && j < range.length; i++, j++) {
+                        itemAt(i).children[1].validator = range[j]
+                        root.addTarget(itemAt(i).children[1])
+                    }
+                }
+            }
+            Label {
+                property int timeindex: 3+curidx*datetime.count
+                anchors.right: parent.right
+                anchors.bottom: parent.bottom
+                text: (timelist.length <= timeindex+2) ? '(-:-:-)' :
+                                                         '('+timelist[timeindex]+':'+timelist[timeindex+1]+':'+timelist[timeindex+2]+')'
+                color: 'gray'
+                font.pixelSize: 20
+            }
+        }
+    }
+    Item { height:blankheight/3 }
+    RowLayout {
+        anchors.left: parent.left
+        anchors.right: parent.right
+        Button {
+            anchors.left: parent.left
+            anchors.leftMargin: 100
+            text: 'Refresh'
+            highlighted: true
+            onClicked: {
+                loglist.currentIndex = -1
+                logplayimpl.refresh()
+            }
+        }
+        Button {
+            anchors.right: parent.right
+            anchors.rightMargin: 100
+            text: playing ? 'Stop' : 'Play'
+            highlighted: true
+            onClicked: {
+                if(playing) {
+                    playing = false
+                    logplayimpl.CANPlay(false)
+                }
+                else {
+                    if(logplayimpl.checkTime(ports.currentText, stime, etime))
+                    {
+                        logplayimpl.setCANProperty(loglist.currentIndex, ports.currentText, stime, etime)
+                        if(logplayimpl.CANPlay(true))
+                            playing = true
+                    }
+                }
+            }
+        }
+    }
+
+    LogPlayImpl { id: logplayimpl }
+
+    onVisibleChanged: {
+        if(visible) {
+            logplayimpl.refresh()
+        }
+        else {
+            resetPosition()
+        }
+    }
+
+    function adjustPosition(offset) {
+        loglist.implicitHeight -= offset
+        loglist.positionViewAtIndex(loglist.currentIndex, ListView.Beginning)
+    }
+
+    function resetPosition() {
+        loglist.implicitHeight = loglist.impheight
+    }
+}
diff --git a/app/logfile/LogSave.qml b/app/logfile/LogSave.qml
new file mode 100644 (file)
index 0000000..32491aa
--- /dev/null
@@ -0,0 +1,238 @@
+/*
+ * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import QtQuick 2.6
+import QtQuick.Layouts 1.3
+import QtQuick.Controls 2.0
+import LogSaveImpl 1.0
+import '..'
+
+ColumnLayout {
+    property int blankheight : 50
+    property bool saving : false
+
+    anchors.left: parent.left
+    anchors.right: parent.right
+
+    Item { height:blankheight }
+    RowLayout {
+        anchors.left: parent.left
+        anchors.right: parent.right
+        Label {
+            text: 'CurPath  :  '
+            color: 'white'
+        }
+        Label {
+            id: logpath
+            text: ''
+            color: 'white'
+            font.italic: true
+            font.pixelSize: 20
+        }
+    }
+
+    // Can log
+    Item { height:blankheight/3 }
+    Image {
+        width: tabbar.width
+        source: '../images/HMI_Settings_DividingLine.svg'
+    }
+    Item { height:blankheight/3 }
+    RowLayout {
+        anchors.left: parent.left
+        anchors.right: parent.right
+        Label { text: 'CAN'; color: '#59FF7F' }
+        Switch { id: canswitch;anchors.right: parent.right }
+    }
+//    Item { height:blankheight/3 }
+    CANLog {}
+
+    // Touch log
+    Item { height:blankheight/3 }
+    Image {
+        width: tabbar.width
+        source: '../images/HMI_Settings_DividingLine.svg'
+    }
+    Item { height:blankheight/3 }
+    RowLayout {
+        anchors.left: parent.left
+        anchors.right: parent.right
+        Label { text: 'Touch'; color: '#59FF7F' }
+        Switch { id: touchswitch;anchors.right: parent.right }
+    }
+//    Item { height:blankheight/3 }
+    TouchLog {}
+
+    // Video log
+    Item { height:blankheight/3 }
+    Image {
+        width: tabbar.width
+        source: '../images/HMI_Settings_DividingLine.svg'
+    }
+    Item { height:blankheight/3 }
+    RowLayout {
+        anchors.left: parent.left
+        anchors.right: parent.right
+        Label { text: 'Video'; color: '#59FF7F' }
+        Switch { id: videoswitch;anchors.right: parent.right }
+    }
+//    Item { height:blankheight/3 }
+    VideoLog { id: videolog }
+
+    //Audio log
+    Item { height:blankheight/3 }
+    Image {
+        width: tabbar.width
+        source: '../images/HMI_Settings_DividingLine.svg'
+    }
+    Item { height:blankheight/3 }
+    RowLayout {
+        anchors.left: parent.left
+        anchors.right: parent.right
+        Label { text: 'Audio'; color: '#59FF7F' }
+        Switch { id: audioswitch;anchors.right: parent.right }
+    }
+//    Item { height:blankheight/3 }
+    AudioLog { id: audiolog }
+
+    //Status bar
+    Item { height:blankheight/3 }
+    Image {
+        width: tabbar.width
+        source: '../images/HMI_Settings_DividingLine.svg'
+    }
+    Item { height:blankheight/3 }
+    RowLayout {
+        Label {
+            text: 'Status: '
+            color: '#59FF7F'
+        }
+        Label {
+            id: recordstatus
+            property int hour: 0
+            property int minute: 0
+            property int second: 0
+            property string duration: ''
+            text: saving ? ('Log Saving... '+ duration) : (hour > 0 || minute > 0 || second > 0) ? ('Duration: ' + duration) : 'Press SaveStart to save log file.'
+            font.pixelSize: 30
+            Timer {
+                id: timer
+                property double seconds: 0
+                interval: 1000
+                running: false
+                repeat: true
+                onTriggered: {
+                    if(saving) {
+                        seconds++
+                        parent.hour = seconds/(60*60)
+                        parent.minute = parent.hour > 0 ? seconds%(60*60)/60 : seconds/60
+                        parent.second = seconds - parent.hour*(60*60) - parent.minute*60
+                        parent.duration = (parent.hour > 0 ? (parent.hour + 'h ') : '')+(parent.minute > 0 ? (parent.minute + 'm ') : '')+(parent.second > 0 ? (parent.second + 's') : '')
+                    }
+                }
+            }
+        }
+    }
+
+    // Buttons
+    Item { height:blankheight/3 }
+    RowLayout {
+        anchors.left: parent.left
+        anchors.right: parent.right
+        Button {
+            id: savestart
+            anchors.horizontalCenter: parent.horizontalCenter
+            text: saving ? 'SaveStop' : 'SaveStart'
+            highlighted: true
+            onClicked: {
+                if(!saving && (canswitch.checked || touchswitch.checked || videoswitch.checked || audioswitch.checked)) {
+                    if(logsaveimpl.createLogFolders()) {
+                        logpath.text = logsaveimpl.getCurrentSeg()
+
+                        if(canswitch.checked) {
+                            logsaveimpl.setCANProperty()
+                        }
+
+                        if(touchswitch.checked) {
+                            logsaveimpl.setTouchProperty()
+                        }
+
+                        if(videoswitch.checked) {
+                            logsaveimpl.setVideoProperty(videolog.properties)
+                        }
+
+                        if(audioswitch.checked) {
+                            logsaveimpl.setAudioProperty(audiolog.currentsps)
+                        }
+
+                        console.log("touchswitch.checked: " + touchswitch.checked)
+                        if(logsaveimpl.saveStart(canswitch.checked, touchswitch.checked, videoswitch.checked, audioswitch.checked)) {
+                            recordstatus.hour = recordstatus.minute = recordstatus.second = 0
+                            recordstatus.duration = ''
+                            timer.seconds = 0
+                            timer.start()
+                            saving = true
+                        }
+                    }
+                }else if(saving) {
+                    logsaveimpl.saveStop()
+                    saving = false
+                    timer.stop()
+                }
+            }
+        }
+    }
+    LogSaveImpl {
+        id: logsaveimpl
+    }
+    Component.onCompleted: {
+        if(logsaveimpl.createTripFolder()) {
+            logpath.text = trippath = logsaveimpl.getCurrentTrip()
+        }
+        else {
+            logpath.text = ""
+        }
+    }
+
+    onVisibleChanged: {
+        if(!visible) {
+            resetPosition()
+        }
+    }
+
+    function adjustPosition(offset) {
+        y -= offset
+        var heights = 0
+        for(var child in children) {
+            heights += children[child].height
+            if(heights <= offset) {
+                children[child].opacity = 0
+            }
+            else {
+                children[child].opacity = 0
+                break
+            }
+        }
+    }
+
+    function resetPosition() {
+        var children = logsave.children
+        for(var child in children) {
+            children[child].opacity = 1
+        }
+        logsave.y = 0
+    }
+}
diff --git a/app/logfile/TouchLog.qml b/app/logfile/TouchLog.qml
new file mode 100644 (file)
index 0000000..780e186
--- /dev/null
@@ -0,0 +1,13 @@
+import QtQuick 2.6
+import QtQuick.Layouts 1.1
+import QtQuick.Controls 2.0
+import '..'
+
+ColumnLayout {
+    anchors.left: parent.left
+    anchors.leftMargin: 100
+    Label {
+        text: 'There is no property which needs to be set.'
+        font.pixelSize: 30
+    }
+}
diff --git a/app/logfile/TouchLogPlay.qml b/app/logfile/TouchLogPlay.qml
new file mode 100644 (file)
index 0000000..dc12a74
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import QtQuick 2.6
+import QtQuick.Layouts 1.1
+import QtQuick.Controls 2.0
+import TouchLogPlayImpl 1.0
+import '..'
+
+ColumnLayout {
+    property int blankheight : 50
+    property bool playing: false
+
+    anchors.left: parent.left
+    anchors.right: parent.right
+
+    Item { height:blankheight }
+
+    // Title
+    RowLayout{
+        anchors.left: parent.left
+        anchors.right: parent.right
+        Label { text: 'Touch Log files: ' ; color: '#59FF7F'}
+    }
+
+    Item { height:blankheight/3 }
+    Image { source: '../images/HMI_Settings_DividingLine.svg' }
+    Item { height:blankheight/3 }
+
+    // List view
+    ListView {
+        id: touchloglist
+        property int impheight: 0
+        property int listitemheight : 50
+        property int listmaxheight : 600
+
+        anchors.left: parent.left
+        anchors.right: parent.right
+        anchors.margins: 20
+        implicitHeight: 0
+        clip: true
+        model:touchlogplayimpl
+        delegate: MouseArea {
+            height: touchloglist.listitemheight
+            width: ListView.view.width
+            Label {
+                anchors.right: parent.right
+                anchors.bottom: parent.bottom
+                visible: model.children > 0 ? true : false
+                text: '' + model.children
+                color: 'gray'
+                font.pixelSize: 30
+            }
+            Image {
+                source: '../images/HMI_Settings_DividingLine.svg'
+                anchors.horizontalCenter: parent.horizontalCenter
+                anchors.top: parent.top
+                visible: model.index > 0
+            }
+            Image {
+                visible: touchloglist.currentIndex === model.index ? true : false
+                anchors.fill: parent
+                source:'./images/HMI_Settings_Button_Cancel.svg'
+            }
+            Label {
+                anchors.left: parent.left
+                anchors.bottom: parent.bottom
+                anchors.margins: 5
+                text: model.folder ? model.name : ' > ' + model.name
+                color: model.folder ? 'gray' : (touchloglist.currentIndex === model.index ? 'orange' : 'white')
+                font.pixelSize: 30
+            }
+            onClicked: {
+                if(!model.folder) {
+                    touchloglist.currentIndex = model.index
+                }
+            }
+        }
+        onCountChanged: {
+            impheight = (count * listitemheight) > listmaxheight ? listmaxheight : (count * listitemheight)
+            implicitHeight = impheight
+        }
+
+        Component.onCompleted: {
+            currentIndex = -1
+        }
+        onCurrentIndexChanged: {
+            model.setLogFileIndex(currentIndex)
+        }
+    }
+
+    Item { height:blankheight/3 }
+    Image { source: '../images/HMI_Settings_DividingLine.svg' }
+    Item { height:blankheight/3 }
+
+    Item { height:blankheight/3 }
+    RowLayout {
+        anchors.left: parent.left
+        anchors.right: parent.right
+        Button {
+            anchors.left: parent.left
+            anchors.leftMargin: 100
+            text: 'Refresh'
+            highlighted: true
+            onClicked: {
+                touchloglist.currentIndex = -1
+                touchlogplayimpl.refresh()
+            }
+        }
+        Button {
+            id:playstopbutton
+            anchors.right: parent.right
+            anchors.rightMargin: 100
+            text: touchlogplayimpl.propTouchPlayFlag ? 'Stop' : 'Play'
+            highlighted: true
+
+            onClicked: {
+                console.log("status:", playing);
+                if(playing) {
+                    touchlogplayimpl.touchPlay(false)
+                }
+                else {
+                    touchlogplayimpl.setTouchProperty(touchloglist.currentIndex)
+                    touchlogplayimpl.touchPlay(true)
+                }
+            }
+        }
+    }
+
+    TouchLogPlayImpl {
+        id: touchlogplayimpl
+
+        onPropTouchPlayFlagChanged: {
+            console.log("onPropTouchPlayFlagChanged:", touchlogplayimpl.propTouchPlayFlag);
+            if(touchlogplayimpl.propTouchPlayFlag) {
+                playstopbutton.text = "Stop"
+            } else {
+                playstopbutton.text = "Play"
+            }
+        }
+    }
+
+    onVisibleChanged: {
+        if(visible) {
+            touchlogplayimpl.refresh()
+        }
+        else {
+            resetPosition()
+        }
+    }
+
+    function adjustPosition(offset) {
+        touchloglist.implicitHeight -= offset
+        touchloglist.positionViewAtIndex(touchloglist.currentIndex, ListView.Beginning)
+    }
+
+    function resetPosition() {
+        touchloglist.implicitHeight = touchloglist.impheight
+    }
+}
diff --git a/app/logfile/VideoLog.qml b/app/logfile/VideoLog.qml
new file mode 100644 (file)
index 0000000..34105cb
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import QtQuick 2.6
+import QtQuick.Layouts 1.1
+import QtQuick.Controls 2.0
+import '..'
+
+RowLayout {
+    id: videolog
+
+    property var properties: ['', 0, 0,0]
+
+    property int part1width: 250
+    property int part2width: 600
+    property int partheight: 50
+    property int part1fontsize: 30
+    property int part2fontsize: 30
+    property var cameradevs: []
+
+    ColumnLayout{
+        Repeater {
+            model: ['Zone  :  ', 'FPS  :  ', 'Width  :  ', 'Height  :  ']
+            delegate: Item {
+                implicitWidth: part1width
+                implicitHeight: partheight
+                Label {
+                    anchors.right: parent.right
+                    anchors.bottom: parent.bottom
+                    font.pixelSize: part1fontsize
+                    text: model.modelData
+                }
+            }
+        }
+    }
+    ColumnLayout{
+//        RowLayout{
+//            implicitWidth: part2width
+//            implicitHeight: partheight
+//            ButtonGroup {
+//                id: zonegroup
+//            }
+//            Repeater {
+//                id: zones
+//                model: ['None', 'Front', 'Rear', 'Left', 'Right']
+//                delegate: CheckBox {
+//                    text: model.modelData
+//                    font.family: 'Roboto'
+//                    font.pixelSize: part2fontsize
+//                    ButtonGroup.group: zonegroup
+//                    contentItem: Text {
+//                        text: parent.text
+//                        font: parent.font
+//                        color:'white'
+//                        horizontalAlignment: Text.AlignHCenter
+//                        verticalAlignment: Text.AlignVCenter
+//                        leftPadding: parent.indicator.width + parent.spacing
+//                    }
+//                    onCheckedChanged: {
+//                        if(checked) {
+//                            properties[0] = text
+//                        }
+//                    }
+//                }
+//                Component.onCompleted: {
+//                    zones.itemAt(0).checked = true
+//                }
+//            }
+//        }
+
+        ComboBox {
+            id: camerainfo
+            implicitWidth: part2width
+            font.pixelSize: 25
+            model: cameradevs
+            contentItem: Text {
+                text: camerainfo.displayText
+                font: camerainfo.font
+                color: camerainfo.pressed ? "#17a81a" : "white"
+                horizontalAlignment: Text.AlignLeft
+                verticalAlignment: Text.AlignVCenter
+                elide: Text.ElideRight
+            }
+            indicator: Canvas {
+                id: canvas
+                x: camerainfo.width - width - camerainfo.rightPadding
+                y: camerainfo.topPadding + (camerainfo.availableHeight - height) / 2
+                width: 20
+                height: 12
+                contextType: "2d"
+
+                Connections {
+                    target: camerainfo
+                    onPressedChanged: {
+                        canvas.requestPaint()
+                        properties[0] = camerainfo.displayText
+                        console.log("onPressedChanged", properties[0])
+                    }
+                }
+
+                onPaint: {
+                    context.reset();
+                    context.moveTo(0, 0);
+                    context.lineTo(width, 0);
+                    context.lineTo(width / 2, height);
+                    context.closePath();
+                    context.fillStyle = camerainfo.pressed ? "#17a81a" : "white";
+                    context.fill();
+                }
+            }
+            popup: Popup {
+                id: popup
+                y: camerainfo.height - 1
+                implicitWidth: camerainfo.width
+                implicitHeight: listview.count > 6 ? (listview.contentHeight/3.3) : listview.contentHeight
+                padding: 0
+
+                contentItem: ListView {
+                    id: listview
+                    clip: true
+                    model: camerainfo.visible ? camerainfo.delegateModel : null
+                    currentIndex: camerainfo.highlightedIndex
+                    ScrollIndicator.vertical: ScrollIndicator { }
+                }
+
+                background: Image { source: "images/camerainfo_bg.svg" }
+            }
+            delegate: ItemDelegate {
+                id: popupdelegate
+                width: camerainfo.width
+                contentItem: Item {
+                    implicitHeight: 30
+                    Text {
+                        text: modelData
+                        color: popupdelegate.pressed ||  highlighted ? "#21be2b" : "white"
+                        font: camerainfo.font
+                        elide: Text.ElideRight
+                        verticalAlignment: Text.AlignVCenter
+                    }
+                }
+                highlighted: camerainfo.highlightedIndex == index
+            }
+
+            background: Image { source: "images/camerainfo_bg.svg" }
+
+            onCurrentTextChanged: {
+                properties[0] = camerainfo.currentText
+                console.log("onCurrentTextChanged", properties[0])
+            }
+        }
+
+        Repeater {
+            id: textfields
+            property list<IntValidator> range: [
+                IntValidator{bottom: 0; top: 100;},
+                IntValidator{bottom: 0; top: 2000;},
+                IntValidator{bottom: 0; top: 2000;}
+            ]
+            model: ['(0~100)', '(0~2000)', '(0~2000)']
+            delegate: TextField {
+                implicitWidth: part2width
+                implicitHeight: partheight
+                color: 'white'
+                font.pixelSize: part2fontsize
+                verticalAlignment: TextInput.AlignBottom
+                Label {
+                    anchors.right: parent.right
+                    anchors.bottom: parent.bottom
+                    text: model.modelData
+                    color: 'gray'
+                    font.pixelSize: 20
+                }
+                onTextChanged: {
+                    if(text == '0') {
+                        text = ''
+                    }
+                    if(model.index + 1 < properties.length) {
+                        properties[model.index + 1] = text
+                    }
+                }
+                onFocusChanged: {
+                    root.updateKeyBoard()
+                }
+            }
+            Component.onCompleted: {
+                for(var i = 0; i < textfields.count && i < range.length; i++) {
+                    textfields.itemAt(i).validator = range[i]
+                    root.addTarget(textfields.itemAt(i))
+                }
+            }
+        }
+    }
+
+    Component.onCompleted: {
+        logsaveimpl.enumerateCameras();
+        cameradevs = logsaveimpl.cameradevs();
+        properties[0] = cameradevs[0]
+        console.log(properties[0]);
+    }
+}
diff --git a/app/logfile/images/HMI_Settings_Button_Cancel.svg b/app/logfile/images/HMI_Settings_Button_Cancel.svg
new file mode 100644 (file)
index 0000000..4251412
--- /dev/null
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+
+<svg
+   xmlns:i="&amp;#38;ns_ai;"
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   version="1.1"
+   id="Layer_1"
+   x="0px"
+   y="0px"
+   viewBox="0 0 151 51"
+   style="enable-background:new 0 0 151 51;"
+   xml:space="preserve"
+   inkscape:version="0.91 r13725"
+   sodipodi:docname="HMI_Settings_TimeDate_Button_Cancel.svg"><metadata
+     id="metadata33"><rdf:RDF><cc:Work
+         rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
+     id="defs31" /><sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="2560"
+     inkscape:window-height="1464"
+     id="namedview29"
+     showgrid="false"
+     inkscape:zoom="4.4503311"
+     inkscape:cx="-69.095982"
+     inkscape:cy="25.5"
+     inkscape:window-x="0"
+     inkscape:window-y="0"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="Layer_1" /><style
+     type="text/css"
+     id="style3">
+       .st0{fill:none;stroke:url(#SVGID_1_);stroke-miterlimit:10;}
+       .st1{opacity:0.3;fill:url(#SVGID_2_);}
+       .st2{fill:#FFFFFF;}
+       .st3{font-family:'Roboto-Regular';}
+       .st4{font-size:20px;}
+       .st5{letter-spacing:3;}
+</style><switch
+     id="switch5"><g
+       i:extraneous="self"
+       id="g7"><g
+         id="g9"><linearGradient
+           id="SVGID_1_"
+           gradientUnits="userSpaceOnUse"
+           x1="24.7258"
+           y1="75.9063"
+           x2="126.2742"
+           y2="-24.9063"><stop
+             offset="0"
+             style="stop-color:#59FF7F"
+             id="stop12" /><stop
+             offset="1"
+             style="stop-color:#6BFBFF"
+             id="stop14" /></linearGradient><rect
+           x="0.5"
+           y="0.5"
+           class="st0"
+           width="150"
+           height="50"
+           id="rect16" /><linearGradient
+           id="SVGID_2_"
+           gradientUnits="userSpaceOnUse"
+           x1="-25.8746"
+           y1="126.14"
+           x2="190.2191"
+           y2="-88.3878"><stop
+             offset="0"
+             style="stop-color:#59FF7F"
+             id="stop19" /><stop
+             offset="1"
+             style="stop-color:#6BFBFF"
+             id="stop21" /></linearGradient><rect
+           x="0.5"
+           y="0.5"
+           class="st1"
+           width="150"
+           height="50"
+           id="rect23" /></g></g></switch></svg>
\ No newline at end of file
diff --git a/app/logfile/images/HMI_Settings_Button_Ok.svg b/app/logfile/images/HMI_Settings_Button_Ok.svg
new file mode 100644 (file)
index 0000000..dac68d8
--- /dev/null
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+
+<svg
+   xmlns:i="&amp;#38;ns_ai;"
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   version="1.1"
+   id="Layer_1"
+   x="0px"
+   y="0px"
+   viewBox="0 0 151 51"
+   style="enable-background:new 0 0 151 51;"
+   xml:space="preserve"
+   inkscape:version="0.91 r13725"
+   sodipodi:docname="HMI_Settings_TimeDate_Button_Set.svg"><metadata
+     id="metadata33"><rdf:RDF><cc:Work
+         rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
+     id="defs31" /><sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="2560"
+     inkscape:window-height="1464"
+     id="namedview29"
+     showgrid="false"
+     inkscape:zoom="4.4503311"
+     inkscape:cx="-106.17187"
+     inkscape:cy="25.5"
+     inkscape:window-x="0"
+     inkscape:window-y="0"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="Layer_1" /><style
+     type="text/css"
+     id="style3">
+       .st0{fill:none;stroke:url(#SVGID_1_);stroke-miterlimit:10;}
+       .st1{opacity:0.84;fill:url(#SVGID_2_);}
+       .st2{fill:#27232B;}
+       .st3{font-family:'Roboto-Regular';}
+       .st4{font-size:20px;}
+       .st5{letter-spacing:3;}
+</style><switch
+     id="switch5"><g
+       i:extraneous="self"
+       id="g7"><g
+         id="g9"><linearGradient
+           id="SVGID_1_"
+           gradientUnits="userSpaceOnUse"
+           x1="24.7258"
+           y1="75.9063"
+           x2="126.2742"
+           y2="-24.9063"><stop
+             offset="0"
+             style="stop-color:#59FF7F"
+             id="stop12" /><stop
+             offset="1"
+             style="stop-color:#6BFBFF"
+             id="stop14" /></linearGradient><rect
+           x="0.5"
+           y="0.5"
+           class="st0"
+           width="150"
+           height="50"
+           id="rect16" /><linearGradient
+           id="SVGID_2_"
+           gradientUnits="userSpaceOnUse"
+           x1="-25.8746"
+           y1="126.14"
+           x2="190.2191"
+           y2="-88.3878"><stop
+             offset="0"
+             style="stop-color:#59FF7F"
+             id="stop19" /><stop
+             offset="1"
+             style="stop-color:#6BFBFF"
+             id="stop21" /></linearGradient><rect
+           x="0.5"
+           y="0.5"
+           class="st1"
+           width="150"
+           height="50"
+           id="rect23" /></g></g></switch></svg>
\ No newline at end of file
diff --git a/app/logfile/images/HMI_Settings_LogFile.svg b/app/logfile/images/HMI_Settings_LogFile.svg
new file mode 100644 (file)
index 0000000..5c43c9d
--- /dev/null
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+
+<svg
+   xmlns:i="&amp;#38;#38;#38;ns_ai;"
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   version="1.1"
+   id="Layer_1"
+   x="0px"
+   y="0px"
+   viewBox="0 0 100 100"
+   style="enable-background:new 0 0 100 100;"
+   xml:space="preserve"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="LOG2.svg"
+   width="100%"
+   height="100%"><metadata
+     id="metadata20"><rdf:RDF><cc:Work
+         rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
+     id="defs18" /><sodipodi:namedview
+     pagecolor="#54544e"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0.32941176"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1615"
+     inkscape:window-height="917"
+     id="namedview16"
+     showgrid="false"
+     inkscape:zoom="3.337544"
+     inkscape:cx="29.813716"
+     inkscape:cy="60.135712"
+     inkscape:window-x="65"
+     inkscape:window-y="24"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="g7" /><style
+     type="text/css"
+     id="style3">
+       .st0{fill:#FFFFFF;}
+</style><switch
+     id="switch5"><g
+       i:extraneous="self"
+       id="g7"><rect
+         style="fill:#ffffff;fill-opacity:0"
+         id="rect3825"
+         width="39.40678"
+         height="17.79661"
+         x="29.661016"
+         y="23.305084"
+         ry="7.2033896" /><path
+         style="fill:#ffffff;fill-opacity:1;stroke:none"
+         d="m 25.625,30.9375 c -2.112712,0 -3.84375,1.718453 -3.84375,3.84375 l 0,27.46875 c 0,2.125297 1.731038,3.84375 3.84375,3.84375 l 16.9375,0 c 1.879864,0 3.399091,-1.360464 3.71875,-3.15625 l -16.4375,0 c -2.112712,0 -3.8125,-1.718453 -3.8125,-3.84375 l 0,-27.5 c 0,-0.22376 0.05755,-0.443189 0.09375,-0.65625 l -0.5,0 z"
+         id="rect5439"
+         inkscape:connector-curvature="0" /><path
+         style="fill:#ffffff;fill-opacity:1;stroke:none"
+         d="m 49.157183,31.15625 c -6.669621,0 -12.094683,7.815468 -12.094683,17.46875 0,9.653282 5.425062,17.46875 12.094683,17.46875 6.66962,0 12.064745,-7.815468 12.064745,-17.46875 0,-9.653282 -5.395125,-17.46875 -12.064745,-17.46875 z m -0.239499,3.28125 c 4.764015,0 8.621952,6.38311 8.621952,14.28125 0,7.89814 -3.857937,14.3125 -8.621952,14.3125 -4.764015,0 -8.621952,-6.41436 -8.621952,-14.3125 0,-7.89814 3.857937,-14.28125 8.621952,-14.28125 z"
+         id="path5496"
+         inkscape:connector-curvature="0" /><path
+         style="fill:#ffffff;fill-opacity:1;stroke:none"
+         d="M 69.9375 30.84375 C 63.267879 30.84375 57.84375 38.659218 57.84375 48.3125 C 57.84375 57.965782 63.267879 65.78125 69.9375 65.78125 C 76.512166 65.78125 81.849391 58.181821 82 48.71875 L 78.3125 48.71875 C 78.211819 56.472129 74.388192 62.71875 69.6875 62.71875 C 64.923485 62.71875 61.0625 56.30439 61.0625 48.40625 C 61.0625 40.50811 64.923485 34.125 69.6875 34.125 C 73.815246 34.125 77.246493 38.926339 78.09375 45.34375 L 81.8125 45.34375 C 80.839908 37.107133 75.907462 30.84375 69.9375 30.84375 z "
+         id="path5496-9" /><rect
+         style="fill:#ffffff;fill-opacity:1;stroke:none"
+         id="rect5539"
+         width="9.7457628"
+         height="4.4491525"
+         x="70.886818"
+         y="48.691174"
+         rx="0.21186557"
+         ry="2.9228771" /><path
+         sodipodi:type="arc"
+         style="fill:#ffffff;fill-opacity:1;stroke:none"
+         id="path5541"
+         sodipodi:cx="50.186604"
+         sodipodi:cy="65.693336"
+         sodipodi:rx="38.501366"
+         sodipodi:ry="1.9475398"
+         d="m 88.687969,65.693336 a 38.501366,1.9475398 0 1 1 -77.002731,0 38.501366,1.9475398 0 1 1 77.002731,0 z" /></g></switch></svg>
\ No newline at end of file
diff --git a/app/logfile/images/Keyboard_Arrow.svg b/app/logfile/images/Keyboard_Arrow.svg
new file mode 100644 (file)
index 0000000..0b28afe
--- /dev/null
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+
+<svg
+   xmlns:i="&amp;ns_ai;"
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   version="1.1"
+   id="Layer_1"
+   x="0px"
+   y="0px"
+   viewBox="0 0 89.6 119.8"
+   style="enable-background:new 0 0 89.6 119.8;"
+   xml:space="preserve"
+   inkscape:version="0.91 r13725"
+   sodipodi:docname="Keyboard_Arrow.svg"><metadata
+     id="metadata42"><rdf:RDF><cc:Work
+         rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
+     id="defs40" /><sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="2560"
+     inkscape:window-height="1464"
+     id="namedview38"
+     showgrid="false"
+     inkscape:zoom="1.9699499"
+     inkscape:cx="-219.92755"
+     inkscape:cy="59.900002"
+     inkscape:window-x="0"
+     inkscape:window-y="0"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="Layer_1" /><style
+     type="text/css"
+     id="style3">
+       .st0{opacity:0.42;fill:#ACACA5;}
+       .st1{opacity:0.42;fill:url(#SVGID_1_);}
+       .st2{fill:none;stroke:#ACACA5;stroke-miterlimit:10;}
+       .st3{fill:none;stroke:#FFFFFF;stroke-width:2;stroke-miterlimit:10;}
+       .st4{fill:#FFFFFF;}
+</style><switch
+     id="switch5"><g
+       i:extraneous="self"
+       id="g7"><g
+         id="g9"><g
+           id="g28"><g
+             id="g30"><polyline
+               class="st3"
+               points="53.7,44 53.7,71.2 22,71.2      "
+               id="polyline32" /><g
+               id="g34"><path
+                 class="st4"
+                 d="M35.7,61.6c0.3,0.5,0.2,1.1-0.3,1.4l-12.9,8.2l12.9,8.2c0.5,0.3,0.6,0.9,0.3,1.4        c-0.3,0.5-0.9,0.6-1.4,0.3l-14.2-9.1c-0.3-0.2-0.5-0.5-0.5-0.8c0-0.3,0.2-0.7,0.5-0.8l14.2-9.1c0.2-0.1,0.4-0.2,0.5-0.2        C35.2,61.2,35.5,61.3,35.7,61.6z"
+                 id="path36" /></g></g></g></g></g></switch></svg>
\ No newline at end of file
diff --git a/app/logfile/images/Keyboard_Back.svg b/app/logfile/images/Keyboard_Back.svg
new file mode 100644 (file)
index 0000000..e28b58e
--- /dev/null
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+
+<svg
+   xmlns:i="&amp;ns_ai;"
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   version="1.1"
+   id="Layer_1"
+   x="0px"
+   y="0px"
+   viewBox="0 0 78.3 119.8"
+   style="enable-background:new 0 0 78.3 119.8;"
+   xml:space="preserve"
+   inkscape:version="0.91 r13725"
+   sodipodi:docname="Keyboard_Inactive_Back.svg"><metadata
+     id="metadata21"><rdf:RDF><cc:Work
+         rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
+     id="defs19" /><sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="2560"
+     inkscape:window-height="1464"
+     id="namedview17"
+     showgrid="false"
+     inkscape:zoom="1.9699499"
+     inkscape:cx="-229.89238"
+     inkscape:cy="59.900002"
+     inkscape:window-x="0"
+     inkscape:window-y="0"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="Layer_1" /><style
+     type="text/css"
+     id="style3">
+       .st0{opacity:0.42;fill:#ACACA5;}
+       .st1{fill:none;stroke:#ACACA5;stroke-miterlimit:10;}
+       .st2{fill:#FFFFFF;}
+</style><switch
+     id="switch5"><g
+       i:extraneous="self"
+       id="g7"><g
+         id="g9"><path
+           class="st2"
+           d="M61.5,45.1H26.3c-0.5,0-1,0.2-1.3,0.5L10.6,59.9c-0.3,0.3-0.5,0.8-0.5,1.3s0.2,1,0.5,1.3L25,76.9     c0.3,0.3,0.8,0.5,1.3,0.5h35.3c1,0,1.8-0.8,1.8-1.8V46.9C63.4,45.9,62.5,45.1,61.5,45.1z M48.8,65.6c0.9,0.9,0.9,2.2,0,3.1     c-0.8,0.8-2.2,0.8-3.1,0l-4.3-4.3L37,68.7c-0.8,0.9-2.2,0.8-3.1,0c-0.8-0.8-0.9-2.2,0-3.1l4.3-4.3L34,56.9     c-0.8-0.8-0.8-2.2,0-3.1c0.9-0.9,2.2-0.8,3.1,0l4.3,4.3l4.4-4.4c0.8-0.8,2.2-0.8,3.1,0c0.8,0.8,0.8,2.2,0,3.1l-4.4,4.4L48.8,65.6     z"
+           id="path15" /></g></g></switch></svg>
\ No newline at end of file
diff --git a/app/logfile/images/camerainfo_bg.svg b/app/logfile/images/camerainfo_bg.svg
new file mode 100644 (file)
index 0000000..109ffe7
--- /dev/null
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+
+<svg
+   xmlns:i="&amp;#38;ns_ai;"
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   version="1.1"
+   id="Layer_1"
+   x="0px"
+   y="0px"
+   viewBox="0 0 600 51"
+   style="enable-background:new 0 0 600 51;"
+   xml:space="preserve"
+   inkscape:version="0.91 r13725"
+   sodipodi:docname="HMI_Settings_TimeDate_Button_Cancel.svg"><metadata
+     id="metadata33"><rdf:RDF><cc:Work
+         rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
+     id="defs31" /><sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="2560"
+     inkscape:window-height="1464"
+     id="namedview29"
+     showgrid="false"
+     inkscape:zoom="4.4503311"
+     inkscape:cx="-69.095982"
+     inkscape:cy="25.5"
+     inkscape:window-x="0"
+     inkscape:window-y="0"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="Layer_1" /><style
+     type="text/css"
+     id="style3">
+       .st0{fill:none;stroke:url(#SVGID_1_);stroke-miterlimit:10;}
+       .st1{opacity:0.3;fill:url(#SVGID_2_);}
+       .st2{fill:#FFFFFF;}
+       .st3{font-family:'Roboto-Regular';}
+       .st4{font-size:20px;}
+       .st5{letter-spacing:3;}
+</style><switch
+     id="switch5"><g
+       i:extraneous="self"
+       id="g7"><g
+         id="g9"><linearGradient
+           id="SVGID_1_"
+           gradientUnits="userSpaceOnUse"
+           x1="24.7258"
+           y1="75.9063"
+           x2="126.2742"
+           y2="-24.9063"><stop
+             offset="0"
+             style="stop-color:#59FF7F"
+             id="stop12" /><stop
+             offset="1"
+             style="stop-color:#6BFBFF"
+             id="stop14" /></linearGradient><rect
+           x="0.5"
+           y="0.5"
+           class="st0"
+           width="599"
+           height="50"
+           id="rect16" /><linearGradient
+           id="SVGID_2_"
+           gradientUnits="userSpaceOnUse"
+           x1="-25.8746"
+           y1="126.14"
+           x2="190.2191"
+           y2="-88.3878"><stop
+             offset="0"
+             style="stop-color:#59FF7F"
+             id="stop19" /><stop
+             offset="1"
+             style="stop-color:#6BFBFF"
+             id="stop21" /></linearGradient><rect
+           x="0.5"
+           y="0.5"
+           class="st1"
+           width="599"
+           height="50"
+           id="rect23" /></g></g></switch></svg>
diff --git a/app/logfile/keyboard/AbstractKeyboard.qml b/app/logfile/keyboard/AbstractKeyboard.qml
new file mode 100644 (file)
index 0000000..95a0b06
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2016 The Qt Company Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import QtQuick 2.6
+import QtQuick.Window 2.0
+
+Item {
+    id: root
+    implicitWidth: Screen.width
+    implicitHeight: Screen.height / 3
+    signal hide()
+    signal next()
+    property Item target
+}
diff --git a/app/logfile/keyboard/Key.qml b/app/logfile/keyboard/Key.qml
new file mode 100644 (file)
index 0000000..989d108
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2016 The Qt Company Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import QtQuick 2.6
+
+MouseArea {
+    id: root
+    implicitWidth: 50
+    implicitHeight: 80
+    property string text
+    property alias image: image.source
+    property bool touchable: true
+    property bool checkable: false
+    property bool checked: false
+    property bool capital: false
+
+    onClicked: {
+        if (checkable) {
+            checked = !checked
+        } else {
+            if (label.text.length === 1)
+                insert(label.text)
+        }
+    }
+
+    function clearSelctedText() {
+        if (target && target.selectedText.length > 0) {
+            target.remove(target.selectionStart, target.selectionEnd)
+            return true
+        }
+        return false
+    }
+
+    function insert(text) {
+        clearSelctedText()
+        if(target) {
+            target.insert(target.cursorPosition, text)
+        }
+    }
+
+    Rectangle {
+        id: buttonstyle
+        anchors.fill: parent
+        border.width: 2
+        border.color: root.touchable ? 'white' : 'gray'
+        smooth: true
+        radius: root.height / 10
+        color: 'gray'
+        Rectangle {
+            visible: root.touchable
+            anchors.fill: parent
+            radius: parent.radius
+            opacity: root.pressed || root.checked ? 0 : 0.5
+            gradient: Gradient {
+                GradientStop {
+                    position: 0.0
+                    color: 'transparent'
+                }
+                GradientStop {
+                    position: 1.0
+                    color: '#66FF99'
+                }
+            }
+        }
+    }
+
+    Text {
+        id: label
+        anchors.centerIn: parent
+        color: 'white'
+        font.pixelSize: root.height / 2
+        text: root.text
+    }
+
+    Image {
+        id: image
+        anchors.centerIn: parent
+        scale: 0.8
+    }
+}
diff --git a/app/logfile/keyboard/Keyboard.qml b/app/logfile/keyboard/Keyboard.qml
new file mode 100644 (file)
index 0000000..0500e30
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2016 The Qt Company Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import QtQuick 2.6
+import QtQuick.Window 2.0
+import QtQuick.Layouts 1.1
+import QtQuick.Controls 2.0
+
+Item {
+    id: root
+    implicitWidth: Screen.width
+    implicitHeight: Screen.height / 3
+    property Item target
+    property AbstractKeyboard active
+
+    visible: false
+
+    Rectangle {
+        anchors.fill: parent
+        color: 'black'
+        opacity: 0.5
+    }
+
+    MouseArea {
+        anchors.fill: parent
+    }
+}
diff --git a/app/logfile/keyboard/Numbers.qml b/app/logfile/keyboard/Numbers.qml
new file mode 100644 (file)
index 0000000..1d909b7
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2016 The Qt Company Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import QtQuick 2.6
+import QtQuick.Window 2.0
+import QtQuick.Layouts 1.1
+
+AbstractKeyboard {
+    id: root
+
+    ColumnLayout {
+        anchors.fill: parent
+        anchors.margins: root.height / 10
+        RowLayout {
+            Layout.fillWidth: true
+            Layout.fillHeight: true
+            Repeater {
+                model: ['1', '2', '3']
+                delegate: Key {
+                    text: model.modelData
+                    Layout.preferredWidth: 2
+                    Layout.fillWidth: true
+                    Layout.fillHeight: true
+                }
+            }
+            Key {
+                image: '../images/Keyboard_Back.svg'
+                Layout.preferredWidth: 2
+                Layout.fillWidth: true
+                Layout.fillHeight: true
+                onClicked: {
+                    if (!clearSelctedText()) {
+                        if (target && target.cursorPosition > 0)
+                            target.remove(target.cursorPosition - 1, target.cursorPosition)
+                    }
+                }
+            }
+        }
+        RowLayout {
+            Layout.fillWidth: true
+            Layout.fillHeight: true
+            Repeater {
+                model: ['4', '5', '6']
+                delegate: Key {
+                    text: model.modelData
+                    Layout.preferredWidth: 2
+                    Layout.fillWidth: true
+                    Layout.fillHeight: true
+                }
+            }
+            Key {
+                image: '../images/Keyboard_Arrow.svg'
+                Layout.preferredWidth: 2
+                Layout.fillWidth: true
+                Layout.fillHeight: true
+                onClicked: {
+                    root.hide()
+                }
+            }
+        }
+        RowLayout {
+            Layout.fillWidth: true
+            Layout.fillHeight: true
+            Repeater {
+                model: ['7', '8', '9']
+                delegate: Key {
+                    text: model.modelData
+                    Layout.preferredWidth: 2
+                    Layout.fillWidth: true
+                    Layout.fillHeight: true
+                }
+            }
+            Key {
+                text: 'Next'
+                Layout.preferredWidth: 2
+                Layout.fillWidth: true
+                Layout.fillHeight: true
+                onClicked: {
+                    root.next()
+                }
+            }
+        }
+        RowLayout {
+            Layout.fillWidth: true
+            Layout.fillHeight: true
+            Key {
+                text: ' '
+                Layout.preferredWidth: 2
+                Layout.fillWidth: true
+                Layout.fillHeight: true
+                touchable: false
+            }
+            Key {
+                text: '0'
+                Layout.preferredWidth: 2
+                Layout.fillWidth: true
+                Layout.fillHeight: true
+            }
+            Key {
+                text: ' '
+                Layout.preferredWidth: 2
+                Layout.fillWidth: true
+                Layout.fillHeight: true
+                touchable: false
+            }
+            Key {
+                text: 'Clear'
+                Layout.preferredWidth: 2
+                Layout.fillWidth: true
+                Layout.fillHeight: true
+                onClicked: {
+                    target.clear()
+                }
+            }
+        }
+    }
+}
diff --git a/app/logfile/logfile.qrc b/app/logfile/logfile.qrc
new file mode 100644 (file)
index 0000000..b93cf0f
--- /dev/null
@@ -0,0 +1,23 @@
+<RCC>
+    <qresource prefix="/logfile">
+        <file>Bar.qml</file>
+        <file>LogFile.qml</file>
+        <file>LogSave.qml</file>
+        <file>CANLog.qml</file>
+        <file>LogPlay.qml</file>
+        <file>VideoLog.qml</file>
+        <file>AudioLog.qml</file>
+        <file>keyboard/Numbers.qml</file>
+        <file>keyboard/Keyboard.qml</file>
+        <file>keyboard/Key.qml</file>
+        <file>keyboard/AbstractKeyboard.qml</file>
+        <file>images/HMI_Settings_LogFile.svg</file>
+        <file>images/Keyboard_Arrow.svg</file>
+        <file>images/Keyboard_Back.svg</file>
+        <file>images/HMI_Settings_Button_Cancel.svg</file>
+        <file>images/HMI_Settings_Button_Ok.svg</file>
+        <file>TouchLog.qml</file>
+        <file>TouchLogPlay.qml</file>
+        <file>images/camerainfo_bg.svg</file>
+    </qresource>
+</RCC>
diff --git a/app/logfile/logplay.cpp b/app/logfile/logplay.cpp
new file mode 100644 (file)
index 0000000..53febea
--- /dev/null
@@ -0,0 +1,290 @@
+/*
+ * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "logplay.h"
+#include <QDir>
+#include <QDirIterator>
+#include <QDateTime>
+#include <QTextStream>
+#include <sys/wait.h>
+#include <unistd.h>
+
+const std::string LogPlayImpl::PlayUtilsExec = "/usr/bin/canplayer";
+
+LogPlayImpl::LogPlayImpl(QObject *parent) : QAbstractItemModel(parent)
+{
+    roles[nameRole] = "name";
+    roles[folderRole] = "folder";
+    roles[childrenRole] = "children";
+    roles[pathRole] = "path";
+
+    playUtils = -1;
+}
+
+LogPlayImpl::~LogPlayImpl()
+{
+    CANPlay(false);
+}
+
+int LogPlayImpl::rowCount(const QModelIndex &parent) const
+{
+    (void)parent;
+    return datas.size();
+}
+
+int LogPlayImpl::columnCount(const QModelIndex &parent) const
+{
+    (void)parent;
+    return 1;
+}
+
+QModelIndex LogPlayImpl::index(int row, int column, const QModelIndex &parent) const
+{
+    (void)parent;
+    if((row >= 0) && (row < datas.size()))
+    {
+        return createIndex(row,column);
+    }
+    else
+    {
+        return QModelIndex();
+    }
+}
+
+QVariant LogPlayImpl::data(const QModelIndex &index, int role) const
+{
+    if(index.isValid() && index.row()<datas.size())
+    {
+        return datas[index.row()][role];
+    }
+    else
+    {
+        QHash<int,QVariant> data;
+        data[nameRole] = "";
+        data[folderRole] = true;
+        data[childrenRole] = 0;
+        return data[role];
+    }
+}
+
+QModelIndex LogPlayImpl::parent(const QModelIndex &child) const
+{
+    (void)child;
+    return QModelIndex();
+}
+
+QHash<int,QByteArray> LogPlayImpl::roleNames() const
+{
+    return roles;
+}
+
+void LogPlayImpl::refresh()
+{
+    QDir dir(QDir::homePath() + "/" + "LogDataFile");
+
+    if(dir.exists())
+    {
+        beginResetModel();
+        dir.setFilter(QDir::Dirs | QDir::NoDotAndDotDot);
+        dir.setSorting(QDir::Name);
+
+        QFileInfoList list = dir.entryInfoList();
+        datas.clear();
+
+        for(int i = 0; i < list.size(); i++)
+        {
+            QHash<int,QVariant> parent;
+            QStringList children;
+
+            parent[nameRole] = list.at(i).fileName();
+            parent[folderRole] = true;
+            parent[pathRole] = list.at(i).absoluteFilePath();
+
+            children.clear();
+
+            QDirIterator it(list.at(i).filePath(), QStringList() << "*.log", QDir::Files | QDir::NoSymLinks, QDirIterator::Subdirectories);
+            while(it.hasNext())
+            {
+                children << it.next();
+            }
+
+            parent[childrenRole] = children.count();
+            datas.append(parent);
+
+            if(children.count() > 0)
+            {
+                children.sort();
+
+                for(int j = 0; j < children.count(); j++)
+                {
+                    QHash<int,QVariant> child;
+
+                    child[nameRole] = children.at(j).section("/", -1);
+                    child[folderRole] = false;
+                    child[childrenRole] = 0;
+                    child[pathRole] = children.at(j);
+
+                    datas.append(child);
+                }
+            }
+        }
+        endResetModel();
+    }
+}
+
+void LogPlayImpl::setLogFileIndex(int index)
+{
+    startTime.clear();
+    endTime.clear();
+    portsList.clear();
+
+    if(index > 0 && index < datas.size())
+    {
+        QFile file(datas[index][pathRole].toString());
+
+        if(file.exists() && file.open(QIODevice::ReadOnly | QIODevice::Text))
+        {
+            QTextStream filetxt(&file);
+            QString line = "";
+            QString port = "";
+            QDateTime datetime;
+
+            while(!filetxt.atEnd())
+            {
+                line = filetxt.readLine();
+                if(!line.isEmpty())
+                {
+                    port = line.section(" ", 1, 1, QString::SectionSkipEmpty);
+                    if(port.isEmpty())
+                    {
+                        port = line.section("\t", 1, 1, QString::SectionSkipEmpty);
+                    }
+                    datetime = QDateTime::fromTime_t(line.mid(line.indexOf("(")+1, line.indexOf(".")-line.indexOf("(")-1).toUInt());
+                    if(!portsList.contains(port))
+                    {
+                        portsList << port;
+                        startTime[port] << datetime.toString("yyyy") << datetime.toString("MM") << datetime.toString("dd")
+                                        << datetime.toString("hh") << datetime.toString("mm") << datetime.toString("ss");
+                    }
+                    if(endTime.find(port) != endTime.end())
+                    {
+                        endTime[port].clear();
+                    }
+                    endTime[port] << datetime.toString("yyyy") << datetime.toString("MM") << datetime.toString("dd")
+                                  << datetime.toString("hh") << datetime.toString("mm") << datetime.toString("ss");
+                }
+            }
+            file.close();
+        }
+    }
+}
+
+QStringList LogPlayImpl::getCanLogTime(QString port)
+{
+    if(startTime.find(port) != startTime.end() && endTime.find(port) != endTime.end())
+    {
+        return startTime[port] + endTime[port];
+    }
+    else
+    {
+        return QStringList();
+    }
+}
+
+QStringList LogPlayImpl::getPortsList()
+{
+    return portsList;
+}
+
+bool LogPlayImpl::CANPlay(bool play)
+{
+    if(play)
+    {
+        playUtils = fork();
+        switch(playUtils)
+        {
+        case 0:
+            execl(PlayUtilsExec.c_str(), basename(PlayUtilsExec.c_str()),
+                  playUtilsArg["-p"].toStdString().c_str(),
+                  "-I", playUtilsArg["-I"].toStdString().c_str(),
+                  "-l", "i",
+                  (char*)NULL);
+            break;
+        default:
+            break;
+        }
+    }
+    else
+    {
+        if((playUtils > 0) && (kill(playUtils, SIGUSR1) == 0))
+        {
+            waitpid(playUtils, NULL, 0);
+        }
+    }
+
+    return true;
+}
+
+void LogPlayImpl::setCANProperty(int index, QString port, QString stime, QString etime)
+{
+    if(index > 0 && index < datas.size())
+    {
+        playUtilsArg["-p"] = "vcan0="+port;
+        playUtilsArg["-I"] = datas[index][pathRole].toString();
+    }
+}
+
+bool LogPlayImpl::checkTime(QString port, QString stime, QString etime)
+{
+    QString maxtime = "";
+    QString mintime = "";
+
+    if(startTime.find(port) == startTime.end() || endTime.find(port) == endTime.end())
+    {
+        return false;
+    }
+
+    for(int idx = 0; idx < startTime[port].length() && idx < endTime[port].length(); idx++)
+    {
+        mintime += startTime[port].at(idx) + (idx == startTime[port].length() - 1 ? "" : ",");
+        maxtime += endTime[port].at(idx) + (idx == endTime[port].length() - 1 ? "" : ",");
+    }
+
+    if((stime < mintime) || (stime > maxtime) || (etime < mintime) || (etime > maxtime) || (stime > etime))
+    {
+        return false;
+    }
+    else
+    {
+        return true;
+    }
+}
+
+QString LogPlayImpl::convertTimeFormat(QString time)
+{
+    QStringList sep;
+    QString convertstr = "";
+
+    sep << "-" << "-" << "." << ":" << ":";
+
+    //2016-02-08.09:41:59
+    for(int idx = 0; idx <= time.count(","); idx++)
+    {
+        convertstr += time.section(',' , idx, idx) + (idx < sep.length() ? sep.at(idx) : "");
+    }
+
+    return convertstr;
+}
diff --git a/app/logfile/logplay.h b/app/logfile/logplay.h
new file mode 100644 (file)
index 0000000..02b6430
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LOGPLAYIMPPL_H
+#define LOGPLAYIMPPL_H
+
+#include <QAbstractItemModel>
+
+class LogPlayImpl: public QAbstractItemModel
+{
+    Q_OBJECT
+public:
+    explicit LogPlayImpl(QObject *parent = 0);
+    ~LogPlayImpl();
+
+    enum LogPlayImplRoles{
+        nameRole=Qt::UserRole+1,
+        folderRole,
+        childrenRole,
+        pathRole
+    };
+
+    int rowCount(const QModelIndex &parent=QModelIndex()) const Q_DECL_OVERRIDE;
+    int columnCount(const QModelIndex &parent=QModelIndex()) const Q_DECL_OVERRIDE;
+    QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const Q_DECL_OVERRIDE;
+    QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const Q_DECL_OVERRIDE;
+    QModelIndex parent(const QModelIndex &child) const Q_DECL_OVERRIDE;
+    QHash<int,QByteArray> roleNames() const Q_DECL_OVERRIDE;
+
+    Q_INVOKABLE void refresh();
+    Q_INVOKABLE bool CANPlay(bool play);
+    Q_INVOKABLE void setCANProperty(int index, QString port, QString stime, QString etime);
+    Q_INVOKABLE void setLogFileIndex(int index);
+    Q_INVOKABLE QStringList getPortsList();
+    Q_INVOKABLE QStringList getCanLogTime(QString port);
+    Q_INVOKABLE bool checkTime(QString port, QString stime, QString etime);
+
+private:
+    QString convertTimeFormat(QString time);
+
+private:
+    QHash<int,QByteArray> roles;
+    QList<QHash<int,QVariant>> datas;
+    std::map<QString, QStringList> startTime;
+    std::map<QString, QStringList> endTime;
+    QStringList portsList;
+
+    static const std::string PlayUtilsExec;
+
+    pid_t playUtils;
+    std::map<QString, QString> playUtilsArg;
+};
+
+#endif // LOGPLAYIMPPL_H
diff --git a/app/logfile/logsave.cpp b/app/logfile/logsave.cpp
new file mode 100644 (file)
index 0000000..3482cba
--- /dev/null
@@ -0,0 +1,355 @@
+/*
+ * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "logsave.h"
+
+#include <QDateTime>
+#include <QDir>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <opencv2/imgproc.hpp>
+#include <linux/videodev2.h>
+
+const QString LogSaveImpl::TripPre = "Trip_";
+const QString LogSaveImpl::SegPre = "Seg_";
+
+const QString LogSaveImpl::FolderAudio = "AUDIO";
+const QString LogSaveImpl::FolderVideo = "VIDEO";
+const QString LogSaveImpl::FolderCAN = "CAN";
+const QString LogSaveImpl::FolderTouch = "TOUCH";
+const QString LogSaveImpl::FolderOther = "OTHER";
+
+const QString LogSaveImpl::RootFolder = "LogDataFile";
+
+const std::string LogSaveImpl::DumpUtilsExec = "/usr/bin/candump";
+const std::string LogSaveImpl::AudioMixerExec = "/usr/bin/amixer";
+const std::string LogSaveImpl::AudioUtilsExec = "/usr/bin/arecord";
+const std::string LogSaveImpl::VideoUtilsExec = "/usr/bin/videoutils";
+const std::string LogSaveImpl::TouchRecUtilsExec = "/usr/bin/tsrecorder";
+
+LogSaveImpl::LogSaveImpl(QObject *parent):QObject(parent)
+{
+//    videoDevice["None"] = "10";
+//    videoDevice["Front"] = "1";
+//    videoDevice["Right"] = "2";
+//    videoDevice["Left"] = "3";
+//    videoDevice["Rear"] = "4";
+
+    logFolders[FolderAudio] = "";
+    logFolders[FolderVideo] = "";
+    logFolders[FolderCAN] = "";
+    logFolders[FolderOther] = "";
+    logFolders[FolderTouch] = "";
+
+    rootPath = QDir::homePath() + "/" + RootFolder;
+    QDir rootdir(rootPath);
+    if(!rootdir.exists())
+    {
+        if(!rootdir.mkdir(rootPath))
+        {
+            rootPath = "/tmp";
+        }
+    }
+
+    dumpUtils = -1;
+    audioMixer = -1;
+    audioUtils = -1;
+    videoUtils = -1;
+    touchRecUtils = -1;
+}
+
+LogSaveImpl::~LogSaveImpl()
+{
+    saveStop();
+}
+
+void LogSaveImpl::setVideoProperty(QStringList properties)
+{
+    if(properties.length() < 4)
+    {
+        return;
+    }
+
+//    videoUtilsArg["-d"] = videoDevice[properties[0]];
+    videoUtilsArg["-d"] = properties[0].remove("/dev/video");
+    videoUtilsArg["-r"] = (properties[1] != "0" ? properties[1] : "30");
+    videoUtilsArg["-w"] = (properties[2] != "0" ? properties[2] : "640");
+    videoUtilsArg["-h"] = (properties[3] != "0" ? properties[3] : "480");
+    videoUtilsArg["-f"] = logFolders[FolderVideo] + QDateTime::currentDateTime().toString("yyyy_MM_dd_hh_mm_ss") + ".avi";
+}
+
+void LogSaveImpl::setCANProperty()
+{
+    dumpUtilsArg["-L"] = logFolders[FolderCAN] + QDateTime::currentDateTime().toString("yyyy_MM_dd_hh_mm_ss") + ".log";
+}
+
+void LogSaveImpl::setTouchProperty()
+{
+    touchRecUtilsArg["-f"] = logFolders[FolderTouch] + QDateTime::currentDateTime().toString("yyyy_MM_dd_hh_mm_ss") + ".touch";
+}
+
+void LogSaveImpl::setAudioProperty(QString sps)
+{
+    audioUtilsArg["-r"] = (sps != "0" ? sps : "44100");
+    audioUtilsArg["-f"] = logFolders[FolderAudio] + QDateTime::currentDateTime().toString("yyyy_MM_dd_hh_mm_ss") + ".wav";
+}
+
+bool LogSaveImpl::saveStart(bool can, bool touch, bool video, bool audio)
+{
+    qDebug("touch:%d", touch);
+    if(video)
+    {
+        qDebug("-d:%s", videoUtilsArg["-d"].toStdString().c_str());
+        videoUtils = fork();
+        switch(videoUtils)
+        {
+        case 0:
+            execl(VideoUtilsExec.c_str(), basename(VideoUtilsExec.c_str()),
+                  "-d", videoUtilsArg["-d"].toStdString().c_str(),
+                  "-w", videoUtilsArg["-w"].toStdString().c_str(),
+                  "-h", videoUtilsArg["-h"].toStdString().c_str(),
+                  "-r", videoUtilsArg["-r"].toStdString().c_str(),
+                  "-f", videoUtilsArg["-f"].toStdString().c_str(),
+                  "-c", "MP42",
+                  (char *)NULL);
+            break;
+        default:
+            break;
+        }
+    }
+
+    if(can)
+    {
+        int fd;
+        dumpUtils = fork();
+        switch(dumpUtils)
+        {
+        case 0:
+            fd = open(dumpUtilsArg["-L"].toStdString().c_str(), O_CREAT | O_WRONLY, 0666);
+            dup2(fd, 1);
+            close(fd);     /* fd は以後不要なので close() */
+            execl(DumpUtilsExec.c_str(), basename(DumpUtilsExec.c_str()), "vcan0", "-L", (char *)NULL);
+            break;
+        default:
+            break;
+        }
+    }
+
+    if(touch)
+    {
+        touchRecUtils = fork();
+        qDebug("touchRecUtils:%d", touchRecUtils);
+        switch(touchRecUtils)
+        {
+        case 0:
+            qDebug("TouchRecUtilsExec:%s", touchRecUtilsArg["-f"].toStdString().c_str());
+            execl(TouchRecUtilsExec.c_str(), basename(TouchRecUtilsExec.c_str()), "-f", touchRecUtilsArg["-f"].toStdString().c_str(), (char *)NULL);
+            break;
+        default:
+            break;
+        }
+    }
+
+    if(audio)
+    {
+        // Set volume
+        audioMixer = fork();
+        switch(audioMixer)
+        {
+        case 0:
+            execl(AudioMixerExec.c_str(), basename(AudioMixerExec.c_str()), "-D", "hw:ak4613", "cset", "name='DVC In Capture Volume'", "100%", (char*)NULL);
+            break;
+        default:
+            break;
+        }
+        if(audioMixer > 0)
+        {
+            waitpid(audioMixer, NULL, 0);
+        }
+
+        // Set mute off
+        audioMixer = fork();
+        switch(audioMixer)
+        {
+        case 0:
+            execl(AudioMixerExec.c_str(), basename(AudioMixerExec.c_str()), "-D", "hw:ak4613", "cset", "name='DVC In Mute Switch'", "off", (char*)NULL);
+            break;
+        default:
+            break;
+        }
+        if(audioMixer > 0)
+        {
+            waitpid(audioMixer, NULL, 0);
+        }
+
+        // Start record
+        audioUtils = fork();
+        switch(audioUtils)
+        {
+        case 0:
+            execl(AudioUtilsExec.c_str(), basename(AudioUtilsExec.c_str()), "-c", "2", "-f", "S24_LE", "-r", audioUtilsArg["-r"].toStdString().c_str(), "-t", "wav", "-D", "hw:ak4613", audioUtilsArg["-f"].toStdString().c_str(), (char*)NULL);
+            break;
+        default:
+            break;
+        }
+    }
+    return true;
+}
+
+void LogSaveImpl::saveStop()
+{
+    if((videoUtils > 0) && (kill(videoUtils, SIGUSR1) == 0))
+    {
+        waitpid(videoUtils, NULL, 0);
+    }
+
+    if((dumpUtils > 0) && (kill(dumpUtils, SIGUSR1) == 0))
+    {
+        waitpid(dumpUtils, NULL, 0);
+    }
+
+    if((audioUtils > 0) && (kill(audioUtils, SIGKILL) == 0))
+    {
+        waitpid(audioUtils, NULL, 0);
+    }
+
+    if((touchRecUtils > 0) && (kill(touchRecUtils, SIGKILL) == 0))
+    {
+        waitpid(touchRecUtils, NULL, 0);
+    }
+}
+
+bool LogSaveImpl::createLogFolders()
+{
+    bool result = false;
+
+    if(createSegFolder())
+    {
+        QString path;
+        QDir dir;
+
+        result = true;
+
+        for(std::map<QString,QString>::iterator it = logFolders.begin(); it != logFolders.end(); it++)
+        {
+            path = currentSeg + "/" + it->first;
+            if(!dir.exists(path) && !dir.mkdir(path))
+            {
+                it->second = "";
+            }
+            else
+            {
+                it->second = path + "/";
+            }
+        }
+    }
+    return result;
+}
+
+bool LogSaveImpl::createTripFolder()
+{
+    currentTrip = "";
+    if(!rootPath.isEmpty())
+    {
+        QDir tripdir;
+
+        currentTrip = rootPath + "/" + TripPre + QDateTime::currentDateTime().toString("yyyyMMdd_hhmmss");
+
+        if(!tripdir.exists(currentTrip) && !tripdir.mkdir(currentTrip))
+        {
+            currentTrip = "";
+        }
+    }
+
+    if(currentTrip.isEmpty())
+    {
+        return false;
+    }
+    else
+    {
+        return true;
+    }
+}
+
+bool LogSaveImpl::createSegFolder()
+{
+    currentSeg = "";
+
+    if(!currentTrip.isEmpty())
+    {
+        QDir segdir;
+
+        currentSeg = currentTrip + "/" + SegPre + QDateTime::currentDateTime().toString("yyyyMMdd_hhmmss");
+
+        if(!segdir.exists(currentSeg) && !segdir.mkdir(currentSeg))
+        {
+            currentSeg = "";
+        }
+    }
+
+    if(currentSeg.isEmpty())
+    {
+        return false;
+    }
+    else
+    {
+        return true;
+    }
+}
+
+void LogSaveImpl::enumerateCameras() {
+    int maxID = 11;
+    for (int idx = 0; idx <maxID; idx++){
+        std::stringstream  no;
+        no << "/dev/video" << idx;
+        int fd = open(no.str().c_str(), O_RDWR);
+        if (fd != -1){
+            struct v4l2_capability cap;
+
+            if (ioctl(fd,VIDIOC_QUERYCAP,&cap) != -1){
+                if ((cap.capabilities & (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING)) == (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING)){
+                    qDebug("cap.driver %s, cap.card %s, cap.bus_info %s", (char*)(cap.driver), (char*)(cap.card), (char*)(cap.bus_info));
+                    if(strcmp((char*)cap.driver, "uvcvideo") == 0)
+                    {
+                        cameras.push_back(no.str().c_str());  // vector of all available cameras
+                    }
+                }
+            }
+            close(fd);
+        }
+    }
+}
+
+QVariantList LogSaveImpl::cameradevs() const{
+    return cameras;
+}
+
+int LogSaveImpl::cameraCnt() {
+    return cameras.length();
+}
+
+QString LogSaveImpl::getCurrentTrip()
+{
+    return currentTrip;
+}
+
+QString LogSaveImpl::getCurrentSeg()
+{
+    return currentSeg;
+}
diff --git a/app/logfile/logsave.h b/app/logfile/logsave.h
new file mode 100644 (file)
index 0000000..2972fcd
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LOGSAVE_H
+#define LOGSAVE_H
+
+#include <QObject>
+#include <QVariantList>
+
+class LogSaveImpl : public QObject
+{
+    Q_OBJECT
+public:
+    explicit LogSaveImpl(QObject *parent = 0);
+    ~LogSaveImpl();
+
+public:
+    Q_INVOKABLE bool saveStart(bool can, bool touch, bool video, bool audio);
+    Q_INVOKABLE void saveStop();
+    Q_INVOKABLE void setCANProperty();
+    Q_INVOKABLE void setTouchProperty();
+    Q_INVOKABLE void setVideoProperty(QStringList properties);
+    Q_INVOKABLE void setAudioProperty(QString sps);
+    Q_INVOKABLE QString getCurrentTrip();
+    Q_INVOKABLE QString getCurrentSeg();
+    Q_INVOKABLE bool createTripFolder();
+    Q_INVOKABLE bool createLogFolders();
+    Q_INVOKABLE QVariantList cameradevs() const;
+    Q_INVOKABLE void enumerateCameras();
+    Q_INVOKABLE int cameraCnt();
+
+private:
+    bool createSegFolder();
+
+signals:
+    void camraCntChanged(const QVariantList& camcnt);
+
+private:
+    static const QString TripPre;
+    static const QString SegPre;
+
+    static const QString FolderAudio;
+    static const QString FolderVideo;
+    static const QString FolderCAN;
+    static const QString FolderTouch;
+    static const QString FolderOther;
+
+    static const QString RootFolder;
+
+    static const std::string DumpUtilsExec;
+    static const std::string AudioMixerExec;
+    static const std::string AudioUtilsExec;
+    static const std::string VideoUtilsExec;
+    static const std::string TouchRecUtilsExec;
+
+    QString currentSeg;
+    QString currentTrip;
+    QString rootPath;
+//    std::map<QString, QString> videoDevice;
+    std::map<QString, QString> logFolders;
+
+    pid_t dumpUtils;
+    pid_t audioMixer;
+    pid_t audioUtils;
+    pid_t videoUtils;
+    pid_t touchRecUtils;
+
+    QVariantList cameras;
+
+    std::map<QString, QString> dumpUtilsArg;
+    std::map<QString, QString> audioUtilsArg;
+    std::map<QString, QString> videoUtilsArg;
+    std::map<QString, QString> touchRecUtilsArg;
+};
+
+#endif // LOGSAVE_H
diff --git a/app/logfile/touchlogplay.cpp b/app/logfile/touchlogplay.cpp
new file mode 100644 (file)
index 0000000..db7b1a4
--- /dev/null
@@ -0,0 +1,261 @@
+/*
+ * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "touchlogplay.h"
+#include <QDir>
+#include <QDirIterator>
+#include <QDateTime>
+#include <QTextStream>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <signal.h>
+#include <QDebug>
+
+const std::string TouchLogPlayImpl::touchPlayUtilsExec = "/usr/bin/tsplayer";
+TouchLogPlayImpl *TouchLogPlayImpl::pointer = NULL;
+bool TouchLogPlayImpl::touchPlayFlag = false;
+void (*TouchLogPlayImpl::oldHandler)(int) = NULL;
+
+TouchLogPlayImpl::TouchLogPlayImpl(QObject *parent) : QAbstractItemModel(parent)
+{
+    roles[nameRole] = "name";
+    roles[folderRole] = "folder";
+    roles[childrenRole] = "children";
+    roles[pathRole] = "path";
+
+    touchPlayUtils = -1;
+    pointer = this;
+}
+
+TouchLogPlayImpl::~TouchLogPlayImpl()
+{
+    touchPlay(false);
+}
+
+int TouchLogPlayImpl::rowCount(const QModelIndex &parent) const
+{
+    (void)parent;
+    return datas.size();
+}
+
+int TouchLogPlayImpl::columnCount(const QModelIndex &parent) const
+{
+    (void)parent;
+    return 1;
+}
+
+QModelIndex TouchLogPlayImpl::index(int row, int column, const QModelIndex &parent) const
+{
+    (void)parent;
+    if((row >= 0) && (row < datas.size()))
+    {
+        return createIndex(row,column);
+    }
+    else
+    {
+        return QModelIndex();
+    }
+}
+
+QVariant TouchLogPlayImpl::data(const QModelIndex &index, int role) const
+{
+    if(index.isValid() && index.row()<datas.size())
+    {
+        return datas[index.row()][role];
+    }
+    else
+    {
+        QHash<int,QVariant> data;
+        data[nameRole] = "";
+        data[folderRole] = true;
+        data[childrenRole] = 0;
+        return data[role];
+    }
+}
+
+QModelIndex TouchLogPlayImpl::parent(const QModelIndex &child) const
+{
+    (void)child;
+    return QModelIndex();
+}
+
+QHash<int,QByteArray> TouchLogPlayImpl::roleNames() const
+{
+    return roles;
+}
+
+void TouchLogPlayImpl::refresh()
+{
+    QDir dir(QDir::homePath() + "/" + "LogDataFile");
+
+    if(dir.exists())
+    {
+        beginResetModel();
+        dir.setFilter(QDir::Dirs | QDir::NoDotAndDotDot);
+        dir.setSorting(QDir::Name);
+
+        QFileInfoList list = dir.entryInfoList();
+        datas.clear();
+
+        for(int i = 0; i < list.size(); i++)
+        {
+            QHash<int,QVariant> parent;
+            QStringList children;
+
+            parent[nameRole] = list.at(i).fileName();
+            parent[folderRole] = true;
+            parent[pathRole] = list.at(i).absoluteFilePath();
+
+            children.clear();
+
+            QDirIterator it(list.at(i).filePath(), QStringList() << "*.touch", QDir::Files | QDir::NoSymLinks, QDirIterator::Subdirectories);
+            while(it.hasNext())
+            {
+                children << it.next();
+            }
+
+            parent[childrenRole] = children.count();
+            datas.append(parent);
+
+            if(children.count() > 0)
+            {
+                children.sort();
+
+                for(int j = 0; j < children.count(); j++)
+                {
+                    QHash<int,QVariant> child;
+
+                    child[nameRole] = children.at(j).section("/", -1);
+                    child[folderRole] = false;
+                    child[childrenRole] = 0;
+                    child[pathRole] = children.at(j);
+
+                    datas.append(child);
+                }
+            }
+        }
+        endResetModel();
+    }
+}
+
+void TouchLogPlayImpl::setLogFileIndex(int index)
+{
+    if(index > 0 && index < datas.size())
+    {
+        QFile file(datas[index][pathRole].toString());
+
+        if(file.exists() && file.open(QIODevice::ReadOnly | QIODevice::Text))
+        {
+            QTextStream filetxt(&file);
+            QString line = "";
+            QString port = "";
+            QDateTime datetime;
+
+            while(!filetxt.atEnd())
+            {
+                line = filetxt.readLine();
+                if(!line.isEmpty())
+                {
+                    port = line.section(" ", 1, 1, QString::SectionSkipEmpty);
+                    if(port.isEmpty())
+                    {
+                        port = line.section("\t", 1, 1, QString::SectionSkipEmpty);
+                    }
+                    datetime = QDateTime::fromTime_t(line.mid(line.indexOf("(")+1, line.indexOf(".")-line.indexOf("(")-1).toUInt());
+                }
+            }
+            file.close();
+        }
+    }
+}
+
+bool TouchLogPlayImpl::touchPlay(bool play)
+{
+    qDebug() << "touchPlayFlag:" << touchPlayFlag;
+    if(play)
+    {
+        oldHandler = signal(SIGCHLD, finalizeChild);
+        if(oldHandler == SIG_ERR)
+        {
+            qDebug("signal error.");
+            return false;
+        }
+
+        touchPlayUtils = fork();
+        switch(touchPlayUtils)
+        {
+        case 0:
+            execl(touchPlayUtilsExec.c_str(), basename(touchPlayUtilsExec.c_str()),
+                  "-d", "1",
+                  "-f", touchplayUtilsArg["-f"].toStdString().c_str(),
+                  "-e", "1",
+                  (char*)NULL);
+            break;
+        default:
+            touchPlayFlag = true;
+            emit propTouchPlayFlagChanged();
+            qDebug() << "default:";
+            break;
+        }
+    }
+    else
+    {
+        if(touchPlayFlag)
+        {
+            if((touchPlayUtils > 0) && (kill(touchPlayUtils, SIGUSR1) == 0))
+            {
+                waitpid(touchPlayUtils, NULL, 0);
+            }
+        }
+    }
+
+    return true;
+}
+
+void TouchLogPlayImpl::setTouchProperty(int index)
+{
+    if(index > 0 && index < datas.size())
+    {
+        touchplayUtilsArg["-f"] = datas[index][pathRole].toString();
+    }
+}
+
+bool TouchLogPlayImpl::propTouchPlayFlag() const
+{
+    return touchPlayFlag;
+}
+
+void TouchLogPlayImpl::propTouchPlayFlagChangedDelegate()
+{
+    emit propTouchPlayFlagChanged();
+}
+
+void TouchLogPlayImpl::finalizeChild(int sig)
+{
+    if(sig == SIGCHLD)
+    {
+        qDebug("finalizeChild start.");
+        waitpid(-1, NULL, 0);
+        touchPlayFlag = false;
+        emit pointer->propTouchPlayFlagChangedDelegate();
+        qDebug("finalizeChild end.");
+    }
+
+    if(signal(SIGCHLD, oldHandler) == SIG_ERR)
+    {
+        qDebug("signal error.");
+    }
+}
diff --git a/app/logfile/touchlogplay.h b/app/logfile/touchlogplay.h
new file mode 100644 (file)
index 0000000..846bc7d
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TOUCHLOGPLAY_H
+#define TOUCHLOGPLAY_H
+
+#include <QAbstractItemModel>
+
+class TouchLogPlayImpl: public QAbstractItemModel
+{
+    Q_OBJECT
+    Q_PROPERTY(bool propTouchPlayFlag READ propTouchPlayFlag NOTIFY propTouchPlayFlagChanged)
+public:
+    explicit TouchLogPlayImpl(QObject *parent = 0);
+    ~TouchLogPlayImpl();
+
+    enum TouchLogPlayImplRoles {
+        nameRole=Qt::UserRole+1,
+        folderRole,
+        childrenRole,
+        pathRole
+    };
+
+    int rowCount(const QModelIndex &parent=QModelIndex()) const Q_DECL_OVERRIDE;
+    int columnCount(const QModelIndex &parent=QModelIndex()) const Q_DECL_OVERRIDE;
+    QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const Q_DECL_OVERRIDE;
+    QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const Q_DECL_OVERRIDE;
+    QModelIndex parent(const QModelIndex &child) const Q_DECL_OVERRIDE;
+    QHash<int,QByteArray> roleNames() const Q_DECL_OVERRIDE;
+
+    bool propTouchPlayFlag() const;
+
+    Q_INVOKABLE void refresh();
+    Q_INVOKABLE bool touchPlay(bool play);
+    Q_INVOKABLE void setTouchProperty(int index);
+    Q_INVOKABLE void setLogFileIndex(int index);
+
+    void propTouchPlayFlagChangedDelegate();
+    static void finalizeChild(int sig);
+
+signals:
+    void propTouchPlayFlagChanged();
+
+private:
+    QHash<int,QByteArray> roles;
+    QList<QHash<int,QVariant>> datas;
+
+    static const std::string touchPlayUtilsExec;
+    static void (*oldHandler)(int);
+
+    pid_t touchPlayUtils;
+    std::map<QString, QString> touchplayUtilsArg;
+
+    static TouchLogPlayImpl *pointer;
+    static bool touchPlayFlag;
+};
+
+#endif // TOUCHLOGPLAY_H
index 3b39810..58abd30 100644 (file)
 #include <network.h>
 #include <qlibwindowmanager.h>
 
+#include "logfile/logsave.h"
+#include "logfile/logplay.h"
+#include "logfile/touchlogplay.h"
+
 int main(int argc, char *argv[])
 {
     QString graphic_role = QString("settings"); // defined in layers.json in window manager
@@ -49,6 +53,10 @@ int main(int argc, char *argv[])
     parser.process(app);
     QStringList positionalArguments = parser.positionalArguments();
 
+    qmlRegisterType<LogSaveImpl>("LogSaveImpl", 1, 0, "LogSaveImpl");
+    qmlRegisterType<LogPlayImpl>("LogPlayImpl", 1, 0, "LogPlayImpl");
+    qmlRegisterType<TouchLogPlayImpl>("TouchLogPlayImpl", 1, 0, "TouchLogPlayImpl");
+
     QQmlApplicationEngine engine;
     if (positionalArguments.length() != 2) {
         exit(EXIT_FAILURE);