diff --git a/harbour-weechatrelay.pro b/harbour-weechatrelay.pro index 852ca71..207a364 100644 --- a/harbour-weechatrelay.pro +++ b/harbour-weechatrelay.pro @@ -39,7 +39,8 @@ OTHER_FILES += qml/harbour-weechatrelay.qml \ qml/js/uniqid.js \ qml/pages/BufferView.qml \ qml/js/config.js \ - qml/pages/BufferList.qml + qml/pages/BufferList.qml \ + qml/js/weechatcolors.js HEADERS += \ src/relayconnection.h \ diff --git a/qml/js/buffers.js b/qml/js/buffers.js index 5658e20..0e7a778 100644 --- a/qml/js/buffers.js +++ b/qml/js/buffers.js @@ -16,19 +16,28 @@ .import "moment.js" as M .import "debug.js" as D -var _textListComponent = Qt.createComponent('../pages/TextListComponent.qml'); - function Buffer(pointer, number, name, title) { this.pointer = pointer; this.number = number; this.name = name; this.title = title; - this.textList = _textListComponent.createObject(_parentPage); + // A listmodel where we put the messages of this buffer + this.textList = Qt.createQmlObject('import QtQuick 2.0; ListModel {}', + _parentPage); // Add line to this buffer - this.add = function(moment, str) { - this.textList.add(moment, str); + this.add = function(moment, prefix, str) { + this.textList.insert(0, { + time: moment.format('HH:mm:ss'), + prefix: prefix, + str: str + }); + }; + + // Send input into this buffer + this.input = function(str) { + EQ.command('input 0x' + this.pointer + ' ' + str); }; } @@ -39,7 +48,7 @@ var _buffers = {}; // according to buffer number whenever requested var _buffersList = []; -// Page that will own all of our textlistcomponents +// Page that will own all of our textlistmodels var _parentPage = null; @@ -129,7 +138,7 @@ function lineAdded(data) { var buffer = data.buffer; var date = M.moment(data.date); - _buffers[buffer].add(date, data.message); + _buffers[buffer].add(date, data.prefix, data.message); } function _sortBuffersList() { diff --git a/qml/js/connection.js b/qml/js/connection.js index a09913b..e037a38 100644 --- a/qml/js/connection.js +++ b/qml/js/connection.js @@ -61,13 +61,13 @@ function init(connectionHandler, pageStack) { // Signal handlers for incoming data from connection function newEvent(id, data) { - D.d("Event received: " + id); - D.d(JSON.stringify(data)); + D.c("Event received: " + id); + D.c(JSON.stringify(data)); EQ.handleEvent(id, data); } function onDisplayDebugData(str) { - D.d(str); + D.c(str); } function onConnected() { @@ -89,7 +89,7 @@ function onSslError(errorStrings, startDate, expiryDate, digest) { - D.d("SSL verification error when connecting"); + D.d("SSL verification error when connecting!"); sslVerifyDialog = ps.push("../pages/SslVerifyDialog.qml", { @@ -106,7 +106,9 @@ function onSslError(errorStrings, function connect(connObj) { debugViewPage = ps.replace("../pages/BufferView.qml"); - bufferListPage = ps.pushAttached("../pages/BufferList.qml"); + bufferListPage = ps.pushAttached("../pages/BufferList.qml", { + bufferViewPage: debugViewPage + }); B.setDebugPage(debugViewPage); D.d("Connecting..."); @@ -175,7 +177,7 @@ function clearConnection() { // Send a command to the WeeChat server function send(str) { - D.d("Sending command: " + str); + D.c("Sending command: " + str); handler.send(str); } diff --git a/qml/js/debug.js b/qml/js/debug.js index d575afe..f926428 100644 --- a/qml/js/debug.js +++ b/qml/js/debug.js @@ -14,7 +14,7 @@ var _buffer = null; // Write a line to the debug view (will go to console if debug view isn't open) function debug(str) { if (_buffer !== undefined && _buffer !== null) { - _buffer.add(M.moment(), str); + _buffer.add(M.moment(), 'DEBUG', str); } else { console.log(str); diff --git a/qml/js/eventqueue.js b/qml/js/eventqueue.js index b03b867..2d8795e 100644 --- a/qml/js/eventqueue.js +++ b/qml/js/eventqueue.js @@ -17,8 +17,6 @@ var _pendingEvents = {}; function handleEvent(id, data) { - //D.d("Handling " + id); - //D.d(JSON.stringify(_pendingEvents)); if (id in _pendingEvents) { var c = _pendingEvents[id]; c.callback(data); @@ -44,8 +42,6 @@ function command(command, callback) { if (read_write) { var id = UID.get(); command = "(" + id + ") " + command; - - //D.d("Adding handler for " + id); addHandler(id, callback, true); } diff --git a/qml/js/utils.js b/qml/js/utils.js index 2ff10c3..98bec2e 100644 --- a/qml/js/utils.js +++ b/qml/js/utils.js @@ -1,5 +1,13 @@ +/* + * © Mikko Ahlroth 2014 + * WeeCRApp is open source software. For licensing information, please check + * the LICENCE file. + */ + // Miscellaneous functions for generic use +.pragma library + // Escape strings for Text.StyledText function escapeStyled(string) { string = string.replace('&', '&'); @@ -11,3 +19,8 @@ function escapeStyled(string) { function colored(color, string) { return '' + string + ''; } + +// Return bold text +function bold(string) { + return '' + string + ''; +} diff --git a/qml/js/weechatcolors.js b/qml/js/weechatcolors.js new file mode 100644 index 0000000..8798333 --- /dev/null +++ b/qml/js/weechatcolors.js @@ -0,0 +1,126 @@ +/* + * © Mikko Ahlroth 2014 + * WeeCRApp is open source software. For licensing information, please check + * the LICENCE file. + */ + +// Utilities for parsing WeeChat color codes sent +// in the relay protocol + +.pragma library + +// Protocol specific constants +// Starting bytes +var COLOR_START = 0x19; +var SET_ATTR = 0x1A; +var REMOVE_ATTR = 0x1B; +var RESET = 0x1C; + +var START_RE = /^(\u0019|\u001a|\u001b|\u001c)/; + +// Attributes +var ATTR_BOLD = '*'; +var ATTR_REVERSE = '!'; +var ATTR_ITALIC = '/'; +var ATTR_UNDERLINE = '_'; +var ATTR_KEEP = '|'; + +// A section of text which has the given attributes: +// fgColor: Foreground color as weechat color number +// bgColor: Background color --//-- +// attributes: List of attributes from the selection above, +// except ATTR_KEEP. +function CodedTextSection(str, fgColor, bgColor, attributes) { + this.str = str; + this.fgColor = fgColor; + this.bgColor = bgColor; + this.attributes = attributes; +} + +// Parse coded text and return list of CodedTextSection +function parseString(str) { + var out = []; + var currentMode = null; + var currentFg = null; + var currentBg = null; + var currentAttr = []; + var currentStr = null; + var parts = str.split(START_RE); + + for (var i = 0; i < parts.length; ++i) { + // Every even index is a content part + if ((i % 2) === 0) { + // The first part won't have any extra info + if (i !== 0) { + switch (currentMode) { + case COLOR_START: + currentStr = parseColorStart(parts[i], currentFg, currentBg, currentAttr); + break; + + case SET_ATTR: + currentStr = parseSetAttr(parts[i], currentFg, currentBg, currentAttr); + break; + + case REMOVE_ATTR: + currentStr = parseRemoveAttr(parts[i], currentFg, currentBg, currentAttr); + break; + + case RESET: + currentFg = null; + currentBg = null; + currentAttr = null; + break; + } + } + + out.push(new CodedTextSection(currentStr, currentFg, currentBg, currentAttr)); + } + // The odd parts give the next mode + else { + currentMode = parts[i]; + } + } + + return out; +} + +function parseColorStart(part, currentFg, currentBg, currentAttr) { + var data = null; + + if (part[0] === 'F') { + data = parseASTD(part); + } +} + +function parseSetAttr(part, currentFg, currentBg, currentAttr) { + +} + +function parseRemoveAttr(part, currentFg, currentBg, currentAttr) { + +} + +// Parse STD (standard color), removing it from the beginning of string +function parseSTD(str) { + +} + +// Parse EXT (extended color), --//-- +function parseEXT(str) { + +} + +// Parse attributes + STD +function parseASTD(str) { + +} + +// Parse attributes + EXT +function parseAEXT(str) { + +} + +// Parse single attribute +function parseATTR(str) { + +} diff --git a/qml/pages/AddConnection.qml b/qml/pages/AddConnection.qml index 33368c6..27e724b 100644 --- a/qml/pages/AddConnection.qml +++ b/qml/pages/AddConnection.qml @@ -107,7 +107,9 @@ Dialog { spacing: Theme.paddingLarge DialogHeader { - title: "Save" + title: "Add connection" + acceptText: "Save" + cancelText: "Cancel" } TextField { diff --git a/qml/pages/BufferList.qml b/qml/pages/BufferList.qml index 7370722..f0b0008 100644 --- a/qml/pages/BufferList.qml +++ b/qml/pages/BufferList.qml @@ -12,6 +12,8 @@ import "../js/buffers.js" as B Page { id: bufferListPage + property BufferView bufferViewPage : null; + onVisibleChanged: bufferList.updateList(); SilicaListView { @@ -20,10 +22,13 @@ Page { anchors.fill: parent function updateList() { + bufferListModel.clear(); + var buffers = B.getBuffersByNumber(); for (var i = 0; i < buffers.length; ++i) { bufferListModel.append({ + pointer: buffers[i].pointer, number: buffers[i].number, name: buffers[i].name }); @@ -85,7 +90,9 @@ Page { } onClicked: { - console.log(name + " clicked!"); + var buffer = B.getBuffer(pointer); + bufferViewPage.changeBuffer(buffer); + pageStack.navigateBack(PageStackAction.Animated); } } diff --git a/qml/pages/BufferView.qml b/qml/pages/BufferView.qml index e70e8c6..462c1cf 100644 --- a/qml/pages/BufferView.qml +++ b/qml/pages/BufferView.qml @@ -4,8 +4,6 @@ import "." import "../js/debug.js" as D import "../js/connection.js" as C -import "../js/moment.js" as M -import "../js/buffers.js" as B Page { id: bufferViewPage @@ -14,6 +12,7 @@ Page { property string pointer: ""; property int number: 0; property string name: ""; + property var buffer: null; function setTitle(str) { topic.title = str; @@ -27,20 +26,12 @@ Page { isConnected = false; } - function changeBuffer(buffer) { - var textList = buffer.textList; - - // Replace current list with new list - textListItem = textList; - textListItem.parent = mainFlickable; - // HOW DO I SHOT WEB - //mainFlickable.children.push(textListItem); - //textListItem.anchors.top = topic.bottom; - //textListItem.anchors.bottom = inpuRow.top; - textListItem.width = textListItem.parent.width; - textListItem.clip = true; - - topic.title = buffer.title; + function changeBuffer(newBuffer) { + // Replace current list model with new list + D.c('Changing buffer to ' + newBuffer.name); + buffer = newBuffer; + topic.title = newBuffer.title; + textList.model = newBuffer.textList; } SilicaFlickable { @@ -53,8 +44,13 @@ Page { anchors.top: parent.top } - Item { - id: textListItem + TextListComponent { + id: textList + + anchors.top: topic.bottom + anchors.bottom: inputRow.top + width: parent.width + clip: true } Row { @@ -71,11 +67,10 @@ Page { placeholderText: "Type here" EnterKey.enabled: text.length > 0 - //EnterKey.iconSource: "image://theme/icon-m-send" + EnterKey.iconSource: "image://theme/icon-m-enter-accept" EnterKey.onClicked: { - var buffer = B.getBuffer(inputField.text); if (buffer !== null) { - changeBuffer(buffer); + buffer.input(inputField.text); } inputField.text = ""; diff --git a/qml/pages/SslVerifyDialog.qml b/qml/pages/SslVerifyDialog.qml index 2c90d13..c02ca1f 100644 --- a/qml/pages/SslVerifyDialog.qml +++ b/qml/pages/SslVerifyDialog.qml @@ -49,7 +49,8 @@ Dialog { DialogHeader { id: connectHeader - title: "Connect" + title: "SSL Verification" + acceptText: "Connect" cancelText: "Disconnect" width: sslVerifyFlickable.width } diff --git a/qml/pages/TextListComponent.qml b/qml/pages/TextListComponent.qml index e7a28f3..8610c3b 100644 --- a/qml/pages/TextListComponent.qml +++ b/qml/pages/TextListComponent.qml @@ -6,28 +6,11 @@ import "../js/utils.js" as U SilicaListView { id: textList - function add(datetime, str) { - var snap = false; - if (textList.atYBeginning) { - snap = true; - } - - // The top is the latest message on the bottom - textListModel.insert(0, { "time": datetime.format('HH:mm:ss'), "str": str }); - - if (snap) { - textList.positionViewAtBeginning(); - } - } - function colorTime(time) { return U.colored(Theme.secondaryHighlightColor, time); } - - model: ListModel { id: textListModel } - verticalLayoutDirection: ListView.BottomToTop delegate: ListItem { @@ -36,7 +19,7 @@ SilicaListView { Label { id: messageLabel - text: colorTime(time) + " " + U.escapeStyled(str) + text: colorTime(time) + " " + U.bold(U.escapeStyled(prefix)) + " " + U.escapeStyled(str) wrapMode: Text.WrapAtWordBoundaryOrAnywhere color: Theme.highlightColor