Moar progress, sorry for no commit message

This commit is contained in:
Mikko Ahlroth 2014-09-22 20:54:52 +03:00
parent b9e9c58848
commit efbf4ba81d
11 changed files with 434 additions and 91 deletions

View file

@ -36,7 +36,10 @@ OTHER_FILES += qml/harbour-weechatrelay.qml \
qml/js/debug.js \ qml/js/debug.js \
qml/js/buffers.js \ qml/js/buffers.js \
qml/js/eventqueue.js \ qml/js/eventqueue.js \
qml/js/uniqid.js qml/js/uniqid.js \
qml/pages/BufferView.qml \
qml/js/config.js \
qml/pages/BufferList.qml
HEADERS += \ HEADERS += \
src/relayconnection.h \ src/relayconnection.h \

View file

@ -10,24 +10,75 @@
.pragma library .pragma library
.import QtQuick 2.0 as QQ
.import "eventqueue.js" as EQ .import "eventqueue.js" as EQ
.import "moment.js" as M
.import "debug.js" as D .import "debug.js" as D
function Buffer(id) { var _textListComponent = Qt.createComponent('../pages/TextListComponent.qml');
this.id = id;
this.window = null; function Buffer(pointer, number, name, title) {
this.pointer = pointer;
this.number = number;
this.name = name;
this.title = title;
this.textList = _textListComponent.createObject(_parentPage);
// Add line to this buffer
this.add = function(moment, str) {
this.textList.add(moment, str);
};
} }
// Dict of buffers, pointer as key, for fast referencing
var _buffers = {}; var _buffers = {};
// List of all buffers for easy iteration, will be sorted ascending
// according to buffer number whenever requested
var _buffersList = [];
// Page that will own all of our textlistcomponents
var _parentPage = null;
function init() { function init() {
EQ.addHandler("__weecrapp_ready", connected); EQ.addHandler("__weecrapp_ready", connected);
EQ.addHandler("_buffer_line_added", lineAdded);
}
// Set the given page to be used for the core buffer
// This is so that we can reuse the debug page as the
// WeeChat core buffer
function setDebugPage(page) {
_parentPage = page;
var pointer = '0';
var buffer = new Buffer(pointer, 1, 'weechat', 'Debug/core');
_buffers[pointer] = buffer;
_buffersList.push(buffer);
D.setDebugBuffer(buffer);
page.changeBuffer(buffer);
}
function getBuffer(i) {
if (_buffers.hasOwnProperty(i)) {
return _buffers[i];
}
return null;
}
// Return bufferlist sorted by buffer number
function getBuffersByNumber() {
return _buffersList;
} }
function connected() { function connected() {
EQ.command("hdata buffer:gui_buffers(*) name,number", bufferListData); D.d("Fetching all buffers...");
EQ.command("hdata buffer:gui_buffers(*) full_name,short_name,number,type,title", bufferListData);
EQ.command("sync"); EQ.command("sync");
} }
@ -38,18 +89,51 @@ function disconnected() {
function bufferListData(data) { function bufferListData(data) {
D.d("Got buffer list data:");
data = data[0]; data = data[0];
var buffers = data.objectSets; var buffers = data.objectSets;
for (var i = 0; i < buffers.length; ++i) { for (var i = 0; i < buffers.length; ++i) {
D.d(buffers[i].number + " " + buffers[i].name); var pointer = buffers[i]['__path'][0];
var number = buffers[i].number;
var name = buffers[i].short_name;
var title = buffers[i].title;
var buffer = null;
//EQ.command("sync " + buffers[i].name + " buffer,nicklist"); if (buffers[i].type !== 0) {
// Currently only sync IRC buffers
continue;
}
// If this buffer is the core, merge it to the debug buffer
if (_parentPage !== null && number === 1 && buffers[i].full_name === 'core.weechat') {
_buffers[pointer] = _buffers['0'];
buffer = _buffers['0'];
buffer.pointer = pointer;
buffer.name = name;
buffer.title = title;
buffer.number = number;
}
else {
buffer = new Buffer(pointer, number, name, title);
_buffers[pointer] = buffer;
_buffersList.push(buffer);
}
} }
_sortBuffersList();
} }
function bufferSyncData(data) { // A new line was added to a buffer
function lineAdded(data) {
data = data[0].objectSets[0];
var buffer = data.buffer;
var date = M.moment(data.date);
_buffers[buffer].add(date, data.message);
}
function _sortBuffersList() {
_buffersList.sort(function (a, b) {
return a.number - b.number;
});
} }

62
qml/js/config.js Normal file
View file

@ -0,0 +1,62 @@
.pragma library
/*
* © Mikko Ahlroth 2014
* WeeCRApp is open source software. For licensing information, please check
* the LICENCE file.
*/
/*
* This file contains the configuration settings of the app (both hardcoded
* and user-settable) and the API to change them. Connection-specific settings
* are handled in AddConnection.qml.
*/
.import "storage.js" as S
/*
* Constants that cannot be changed
*/
// Regex to match weechat version strings
var SUPPORTED_WEECHAT_VERSIONS = /^(?:0\.4)|(?:1\.0)/;
/*
* All settings and their defaults
*/
var _s = {
timestamp_format: 'HH:mm:ss'
};
var _init = false;
// Load all settings on first config access
if (!_init) {
_loadConfig();
}
function set(key, value) {
_s[key] = value;
var db = S.connect();
S.storeSetting(db, key, value);
}
function get(key) {
return _s[key];
}
function _loadConfig() {
var db = S.connect();
for (var key in _s) {
var val = S.readSetting(db, key, _s[key]);
}
}

View file

@ -5,6 +5,7 @@
.import "debug.js" as D .import "debug.js" as D
.import "eventqueue.js" as EQ .import "eventqueue.js" as EQ
.import "buffers.js" as B .import "buffers.js" as B
.import "config.js" as C
/* /*
* © Mikko Ahlroth 2014 * © Mikko Ahlroth 2014
@ -25,6 +26,7 @@ var ps = null; // The PageStack
// Views // Views
var debugViewPage = null; var debugViewPage = null;
var bufferListPage = null;
var sslVerifyDialog = null; var sslVerifyDialog = null;
@ -40,11 +42,20 @@ function init(connectionHandler, pageStack) {
}); });
// Wait for init reply to let system know it's ready to send // Wait for init reply to let system know it's ready to send
EQ.addHandler("init", function() { EQ.addHandler("init", function(data) {
EQ.handleEvent("__weecrapp_ready"); // Check the received version, it must match the minimum supported
}); var version = data[0]['value'];
if (!C.SUPPORTED_WEECHAT_VERSIONS.test(version)) {
D.d("This version of WeeChat is not supported.");
disconnect();
}
else {
D.d("Welcome to WeeChat " + version);
EQ.handleEvent("__weecrapp_ready");
}
}, true);
B.init(); B.init(ps);
} }
@ -94,8 +105,9 @@ function onSslError(errorStrings,
// Public API // Public API
function connect(connObj) { function connect(connObj) {
debugViewPage = ps.replace("../pages/DebugView.qml"); debugViewPage = ps.replace("../pages/BufferView.qml");
D.setDebugPage(debugViewPage); bufferListPage = ps.pushAttached("../pages/BufferList.qml");
B.setDebugPage(debugViewPage);
D.d("Connecting..."); D.d("Connecting...");
var connType = (connObj.type === "ssl") var connType = (connObj.type === "ssl")
@ -158,6 +170,7 @@ function clearConnection() {
connection = null; connection = null;
connected = false; connected = false;
handler.clearData(); handler.clearData();
ps.replace("../pages/ConnectionList.qml");
} }
// Send a command to the WeeChat server // Send a command to the WeeChat server

View file

@ -6,21 +6,23 @@
.pragma library .pragma library
.import "moment.js" as M
var _page = null; // Buffer to push messages to
var _buffer = null;
// Write a line to the debug view (will go to console if debug view isn't open) // Write a line to the debug view (will go to console if debug view isn't open)
function debug(str) { function debug(str) {
if (_page != null) { if (_buffer !== undefined && _buffer !== null) {
_page.display(str); _buffer.add(M.moment(), str);
} }
else { else {
console.log(str); console.log(str);
} }
} }
function setDebugPage(o) { function setDebugBuffer(o) {
_page = o; _buffer = o;
} }
@ -28,19 +30,34 @@ function d(str) {
debug(str); debug(str);
} }
// Go straight to console
function c(str) {
console.log(str);
}
function e(o) { function e(o) {
enumerate(o); enumerate(o);
} }
function enumerate(o) { function enumerate(o) {
d("Enumerating " + o); c("Enumerating object");
d("---"); c("---");
var keys = Object.keys(o); var keys = Object.keys(o);
for (var i = 0; i < keys.length; ++i) { for (var i = 0; i < keys.length; ++i) {
d(keys[i] + ": " + o[keys[i]]); var val = o[keys[i]];
if (typeof val === 'undefined') {
c(keys[i] + ": undefined");
}
else if (val === null) {
c(keys[i] + ": null");
}
else {
c(keys[i] + ": " + val);
}
} }
d(""); c("");
} }

View file

@ -45,7 +45,7 @@ function command(command, callback) {
var id = UID.get(); var id = UID.get();
command = "(" + id + ") " + command; command = "(" + id + ") " + command;
D.d("Adding handler for " + id); //D.d("Adding handler for " + id);
addHandler(id, callback, true); addHandler(id, callback, true);
} }

108
qml/pages/BufferList.qml Normal file
View file

@ -0,0 +1,108 @@
/*
* © Mikko Ahlroth 2014
* WeeCRApp is open source software. For licensing information, please check
* the LICENCE file.
*/
import QtQuick 2.0
import Sailfish.Silica 1.0
import "../js/buffers.js" as B
Page {
id: bufferListPage
onVisibleChanged: bufferList.updateList();
SilicaListView {
id: bufferList
model: ListModel { id: bufferListModel }
anchors.fill: parent
function updateList() {
var buffers = B.getBuffersByNumber();
for (var i = 0; i < buffers.length; ++i) {
bufferListModel.append({
number: buffers[i].number,
name: buffers[i].name
});
}
}
header: PageHeader {
width: bufferList.width
title: "Buffers"
}
delegate: ListItem {
id: listItem
contentHeight: Theme.itemSizeSmall
menu: contextMenu
ListView.onRemove: animateRemoval(listItem);
function close() {
remorseAction("Closing buffer",
function() {
// TODO Close buffer forrealz
console.log("Closed " + name + "!");
});
}
Row {
anchors.verticalCenter: parent.verticalCenter
spacing: Theme.paddingLarge
anchors {
left: parent.left
right: parent.right
}
Label {
text: number
color: listItem.highlighted ? Theme.secondaryHighlightColor
: Theme.secondaryColor;
width: parent.width / 7
horizontalAlignment: Qt.AlignRight
}
Label {
text: name
color: listItem.highlighted ? Theme.highlightColor
: Theme.primaryColor;
}
}
Component {
id: contextMenu
ContextMenu {
MenuItem {
text: "Close"
onClicked: close();
}
}
}
onClicked: {
console.log(name + " clicked!");
}
}
VerticalScrollDecorator { flickable: connectionList }
PullDownMenu {
MenuItem {
text: "???"
}
}
PushUpMenu {
MenuItem {
text: "Go to top"
onClicked: bufferList.scrollToTop();
}
}
}
}

101
qml/pages/BufferView.qml Normal file
View file

@ -0,0 +1,101 @@
import QtQuick 2.0
import Sailfish.Silica 1.0
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
property bool isConnected: false;
property string pointer: "";
property int number: 0;
property string name: "";
function setTitle(str) {
topic.title = str;
}
function connected() {
isConnected = true;
}
function disconnected() {
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;
}
SilicaFlickable {
id: mainFlickable
anchors.fill: parent
PageHeader {
id: topic
title: "Debug"
anchors.top: parent.top
}
Item {
id: textListItem
}
Row {
id: inputRow
width: parent.width
anchors.bottom: parent.bottom
TextField {
id: inputField
width: parent.width
anchors.bottom: parent.bottom
placeholderText: "Type here"
EnterKey.enabled: text.length > 0
//EnterKey.iconSource: "image://theme/icon-m-send"
EnterKey.onClicked: {
var buffer = B.getBuffer(inputField.text);
if (buffer !== null) {
changeBuffer(buffer);
}
inputField.text = "";
}
}
}
PushUpMenu {
MenuItem {
text: isConnected? "Disconnect" : "Close";
onClicked: {
if (isConnected) {
C.disconnect();
isConnected = false;
}
else {
C.clearConnection();
}
}
}
}
}
}

View file

@ -15,15 +15,16 @@ Page {
onVisibleChanged: connectionList.updateList(); onVisibleChanged: connectionList.updateList();
PageHeader {
title: "Connections"
}
SilicaListView { SilicaListView {
id: connectionList id: connectionList
model: ListModel { id: connectionModel } model: ListModel { id: connectionModel }
anchors.fill: parent anchors.fill: parent
header: PageHeader {
width: connectionList.width
title: "Connections"
}
delegate: ListItem { delegate: ListItem {
id: listItem id: listItem
contentHeight: Theme.itemSizeLarge contentHeight: Theme.itemSizeLarge
@ -45,7 +46,7 @@ Page {
Label { Label {
text: name text: name
color: listItem.highlighted ? Theme.highlightColor color: listItem.highlighted ? Theme.highlightColor
: Theme.primaryColor : Theme.primaryColor;
anchors { anchors {
left: parent.left left: parent.left
right: parent.right right: parent.right
@ -56,7 +57,7 @@ Page {
Label { Label {
text: host + ":" + port text: host + ":" + port
color: listItem.highlighted ? Theme.secondaryHighlightColor color: listItem.highlighted ? Theme.secondaryHighlightColor
: Theme.secondaryColor : Theme.secondaryColor;
anchors { anchors {
left: parent.left left: parent.left
right: parent.right right: parent.right

View file

@ -6,49 +6,8 @@
import QtQuick 2.0 import QtQuick 2.0
import Sailfish.Silica 1.0 import Sailfish.Silica 1.0
import harbour.weechatrelay.connectionhandler 1.0
import "." import "."
import "../js/connection.js" as C BufferView {
id: fakeDebugView
Page {
id: debugViewPage
property bool isConnected: false;
function display(str) {
debugList.add(new Date(), str);
}
function connected() {
isConnected = true;
}
function disconnected() {
isConnected = false;
}
TextListComponent {
id: debugList
anchors.fill: parent
PushUpMenu {
MenuItem {
text: isConnected? "Disconnect" : "Close";
onClicked: {
if (isConnected) {
C.disconnect();
isConnected = false;
}
else {
C.clearConnection();
pageStack.replace("ConnectionList.qml");
}
}
}
}
VerticalScrollDecorator { flickable: debugList }
}
} }

View file

@ -8,42 +8,35 @@ SilicaListView {
function add(datetime, str) { function add(datetime, str) {
var snap = false; var snap = false;
if (textList.atYEnd) { if (textList.atYBeginning) {
snap = true; snap = true;
} }
textListModel.append({ "time": datetime, "str": str }); // The top is the latest message on the bottom
textListModel.insert(0, { "time": datetime.format('HH:mm:ss'), "str": str });
if (snap) { if (snap) {
textList.positionViewAtEnd(); textList.positionViewAtBeginning();
} }
} }
function formatTime(datetime) { function colorTime(time) {
return U.colored(Theme.secondaryHighlightColor, return U.colored(Theme.secondaryHighlightColor,
padTime(datetime.getHours()) + ':' time);
+ padTime(datetime.getMinutes()) + ':'
+ padTime(datetime.getSeconds()));
}
function padTime(timeInt) {
if (timeInt < 10) {
return '0' + timeInt;
}
return '' + timeInt;
} }
model: ListModel { id: textListModel } model: ListModel { id: textListModel }
verticalLayoutDirection: ListView.BottomToTop
delegate: ListItem { delegate: ListItem {
width: parent.width width: parent.width
contentHeight: messageLabel.height contentHeight: messageLabel.height
Label { Label {
id: messageLabel id: messageLabel
text: formatTime(time) + " " + U.escapeStyled(str) text: colorTime(time) + " " + U.escapeStyled(str)
wrapMode: Text.WrapAtWordBoundaryOrAnywhere wrapMode: Text.WrapAtWordBoundaryOrAnywhere
color: Theme.highlightColor color: Theme.highlightColor
@ -55,4 +48,6 @@ SilicaListView {
textFormat: Text.StyledText textFormat: Text.StyledText
} }
} }
VerticalScrollDecorator { flickable: textList }
} }