From c8318d45ac92a4b9c3a27836598ca643e00e885b Mon Sep 17 00:00:00 2001 From: Bel LaPointe Date: Tue, 26 Feb 2019 17:56:07 -0700 Subject: [PATCH] Initial but not really --- .gitignore | 15 ++ build.sh | 1 + cli.go | 19 +++ gui.go | 5 + mytinytodo/buffer.go | 23 +++ mytinytodo/config.go | 7 + mytinytodo/remote/client.go | 140 ++++++++++++++++++ mytinytodo/remote/config.go | 51 +++++++ mytinytodo/remote/http.go | 99 +++++++++++++ mytinytodo/remote/list.go | 11 ++ mytinytodo/remote/task.go | 12 ++ testdata/quick/build | 1 + testdata/quick/main.go | 20 +++ testdata/quick/qml/application.qml | 148 ++++++++++++++++++++ testdata/widget/build | 1 + testdata/widget/main.go | 218 +++++++++++++++++++++++++++++ 16 files changed, 771 insertions(+) create mode 100644 .gitignore create mode 100755 build.sh create mode 100644 cli.go create mode 100644 gui.go create mode 100644 mytinytodo/buffer.go create mode 100644 mytinytodo/config.go create mode 100644 mytinytodo/remote/client.go create mode 100644 mytinytodo/remote/config.go create mode 100644 mytinytodo/remote/http.go create mode 100644 mytinytodo/remote/list.go create mode 100644 mytinytodo/remote/task.go create mode 100644 testdata/quick/build create mode 100644 testdata/quick/main.go create mode 100644 testdata/quick/qml/application.qml create mode 100644 testdata/widget/build create mode 100644 testdata/widget/main.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..538afba --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +lz4 +rclone +rcloner +Go +cloudly +dockfile +compile.sh +*.swp +*.swo +*pycache* +enc_conf +vendor +rproxy3 +cli +gui diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..aea693e --- /dev/null +++ b/build.sh @@ -0,0 +1 @@ +qtdeploy test desktop ${PWD#${GOPATH}/src/} diff --git a/cli.go b/cli.go new file mode 100644 index 0000000..f8a8913 --- /dev/null +++ b/cli.go @@ -0,0 +1,19 @@ +package main + +import ( + "local/mytinytodoclient/mytinytodo/remote" +) + +func main() { + conf, err := remote.NewConfig() + if err != nil { + panic(err) + } + remote, err := remote.NewClient(conf) + if err != nil { + panic(err) + } + if err := remote.ParseArgs(); err != nil { + panic(err) + } +} diff --git a/gui.go b/gui.go new file mode 100644 index 0000000..78b0fc1 --- /dev/null +++ b/gui.go @@ -0,0 +1,5 @@ +package main + +func main() { + panic("gui not implemented") +} diff --git a/mytinytodo/buffer.go b/mytinytodo/buffer.go new file mode 100644 index 0000000..09918ee --- /dev/null +++ b/mytinytodo/buffer.go @@ -0,0 +1,23 @@ +package mytinytodo + +import ( + "local/mytinytodoclient/mytinytodo/remote" + "local/rproxy3/storage" +) + +type Buffer struct { + remote *remote.Client + db storage.DB +} + +func NewBuffer(config *remote.Config) (*Buffer, error) { + remote, err := remote.NewClient(config) + if err != nil { + return nil, err + } + db := storage.NewMap() + return &Buffer{ + remote: remote, + db: db, + }, nil +} diff --git a/mytinytodo/config.go b/mytinytodo/config.go new file mode 100644 index 0000000..e7d45f8 --- /dev/null +++ b/mytinytodo/config.go @@ -0,0 +1,7 @@ +package mytinytodo + +import "local/mytinytodoclient/mytinytodo/remote" + +func NewConfig() (*remote.Config, error) { + return remote.NewConfig() +} diff --git a/mytinytodo/remote/client.go b/mytinytodo/remote/client.go new file mode 100644 index 0000000..a27d9f1 --- /dev/null +++ b/mytinytodo/remote/client.go @@ -0,0 +1,140 @@ +package remote + +import ( + "encoding/json" + "fmt" + "log" + "net/http" + "net/url" +) + +type Client struct { + config *Config + http *http.Client + session *http.Cookie +} + +func NewClient(config *Config) (*Client, error) { + return &Client{ + config: config, + }, nil +} + +func (c *Client) ParseArgs() error { + for i := 0; i < len(c.config.args); i++ { + arg := c.config.args[i] + switch arg { + case "list": + log.Printf("lists: %v", fmt.Sprint(c.Lists())) + case "tasks": + listID := c.config.args[i+1] + i += 1 + log.Printf("tasks: %v", fmt.Sprint(c.Tasks(List{ID: listID}))) + case "new": + listID := c.config.args[i+1] + i += 1 + taskTitle := c.config.args[i+1] + i += 1 + tagsCSV := c.config.args[i+1] + i += 1 + log.Printf("new: %v", fmt.Sprint(c.NewTask(List{ID: listID}, Task{Title: taskTitle}, tagsCSV))) + case "close": + taskID := c.config.args[i+1] + i += 1 + log.Printf("close: %v", fmt.Sprint(c.CloseTask(Task{ID: taskID}))) + case "open": + taskID := c.config.args[i+1] + i += 1 + log.Printf("open: %v", fmt.Sprint(c.OpenTask(Task{ID: taskID}))) + default: + log.Printf("unknown arg %q", arg) + } + } + return nil +} + +func (c *Client) Lists() ([]List, error) { + client, err := NewHTTP(c.config.remote, c.config.password) + if err != nil { + return nil, err + } + var lists loadListsResponse + if resp, err := client.Get("ajax.php?loadLists"); err != nil { + return nil, err + } else if err := json.NewDecoder(resp.Body).Decode(&lists); err != nil { + return nil, fmt.Errorf("cannot read lists: %v", err) + } + return lists.Lists, nil +} + +func (c *Client) Tasks(list List) ([]Task, error) { + client, err := NewHTTP(c.config.remote, c.config.password) + if err != nil { + return nil, err + } + var tasks loadTasksResponse + if resp, err := client.Get("ajax.php?loadTasks&list=" + list.ID); err != nil { + return nil, err + } else if err := json.NewDecoder(resp.Body).Decode(&tasks); err != nil { + return nil, fmt.Errorf("cannot read tasks: %v", err) + } + return tasks.Tasks, nil +} + +func (c *Client) NewTask(list List, task Task, tags string) error { + log.Printf("new: %v < %v", list, task.Title) + client, err := NewHTTP(c.config.remote, c.config.password) + if err != nil { + return err + } + form := url.Values{} + form.Add("list", list.ID) + form.Add("title", task.Title) + form.Add("tag", "/"+tags+"/") + var lists loadListsResponse + if resp, err := client.Post("ajax.php?newTask", form.Encode()); err != nil { + return err + } else if err := json.NewDecoder(resp.Body).Decode(&lists); err != nil { + return fmt.Errorf("cannot make task: %v", err) + } + log.Print(lists) + return nil +} + +func (c *Client) CloseTask(task Task) error { + log.Printf("close: %v", task.ID) + client, err := NewHTTP(c.config.remote, c.config.password) + if err != nil { + return err + } + form := url.Values{} + form.Add("id", task.ID) + form.Add("compl", "1") + var lists loadListsResponse + if resp, err := client.Post("ajax.php?completeTask="+task.ID, form.Encode()); err != nil { + return err + } else if err := json.NewDecoder(resp.Body).Decode(&lists); err != nil { + return fmt.Errorf("cannot close task: %v", err) + } + log.Print(lists) + return nil +} + +func (c *Client) OpenTask(task Task) error { + log.Printf("open: %v", task.ID) + client, err := NewHTTP(c.config.remote, c.config.password) + if err != nil { + return err + } + form := url.Values{} + form.Add("id", task.ID) + form.Add("compl", "0") + var lists loadListsResponse + if resp, err := client.Post("ajax.php?completeTask="+task.ID, form.Encode()); err != nil { + return err + } else if err := json.NewDecoder(resp.Body).Decode(&lists); err != nil { + return fmt.Errorf("cannot close task: %v", err) + } + log.Print(lists) + return nil +} diff --git a/mytinytodo/remote/config.go b/mytinytodo/remote/config.go new file mode 100644 index 0000000..5db2bb9 --- /dev/null +++ b/mytinytodo/remote/config.go @@ -0,0 +1,51 @@ +package remote + +import ( + "flag" + "os" +) + +type Config struct { + remote string + password string + args []string +} + +var globalConfig *Config + +func NewConfig() (*Config, error) { + globalConfig = &Config{} + if err := globalConfig.fromEnv(); err != nil { + return nil, err + } + if err := globalConfig.fromFlags(); err != nil { + return nil, err + } + return globalConfig, nil +} + +func (c *Config) fromFlags() error { + fs := flag.NewFlagSet(os.Args[0], flag.ExitOnError) + remote := fs.String("remote", "https://todo.home.blapointe.com", "remote mytinytodo") + password := fs.String("p", "", "mytinytodo password") + if err := fs.Parse(os.Args[1:]); err != nil { + panic(err) + } + + c.remote = *remote + c.password = *password + c.args = fs.Args() + + return nil +} + +func (c *Config) fromEnv() error { + return nil +} + +func getEnvOrDefault(key, def string) string { + if v, ok := os.LookupEnv(key); ok { + return v + } + return def +} diff --git a/mytinytodo/remote/http.go b/mytinytodo/remote/http.go new file mode 100644 index 0000000..c7f6002 --- /dev/null +++ b/mytinytodo/remote/http.go @@ -0,0 +1,99 @@ +package remote + +import ( + "fmt" + "io" + "io/ioutil" + "net/http" + "net/http/cookiejar" + "net/url" + "strings" +) + +type HTTP struct { + client *http.Client + domain string + password string +} + +func NewHTTP(domain, password string) (*HTTP, error) { + j, _ := cookiejar.New(nil) + //Transport: &http.Transport{Proxy: http.ProxyURL(&url.URL{ + // Host: "localhost:8890", + // Scheme: "http", + //})}, + h := &HTTP{ + client: &http.Client{ + Jar: j, + }, + domain: domain, + password: password, + } + if resp, err := h.Get("/"); err != nil { + return nil, err + } else if resp.StatusCode != 200 { + return nil, fmt.Errorf("bad status from endpoint: %v", resp.StatusCode) + } + if password != "" { + form := url.Values{} + form.Add("login", "1") + form.Add("password", password) + if resp, err := h.Post("ajax.php?login", form.Encode()); err != nil { + return nil, err + } else if b, _ := ioutil.ReadAll(resp.Body); string(b) == `{"logged":0}` { + return nil, fmt.Errorf("bad password") + } else if string(b) != `{"logged":1}` { + return nil, fmt.Errorf("bad login: %q", b) + } + if resp, err := h.Get("/"); err != nil { + return nil, err + } else if resp.StatusCode != 200 { + return nil, fmt.Errorf("bad status from endpoint: %v", resp.StatusCode) + } + } + return h, nil +} + +func (h *HTTP) Get(path string) (*http.Response, error) { + req, err := h.NewReq("GET", path) + if err != nil { + return nil, err + } + return h.Do(req) +} + +func (h *HTTP) Post(path, body string) (*http.Response, error) { + req, err := h.NewReq("POST", path, body) + if err != nil { + return nil, err + } + return h.Do(req) +} + +func (h *HTTP) Do(req *http.Request) (*http.Response, error) { + resp, err := h.client.Do(req) + if err != nil { + return nil, err + } + return resp, nil +} + +func (h *HTTP) NewReq(method string, pathAndBody ...string) (*http.Request, error) { + path := "" + var bodyReader io.Reader + if len(pathAndBody) > 0 { + path = pathAndBody[0] + } + if !strings.HasPrefix(path, "/") { + path = "/" + path + } + if len(pathAndBody) > 1 { + bodyReader = strings.NewReader(pathAndBody[1]) + } + r, err := http.NewRequest(method, h.domain+path, bodyReader) + if err != nil { + return nil, err + } + r.Header.Add("Content-Type", "application/x-www-form-urlencoded") + return r, nil +} diff --git a/mytinytodo/remote/list.go b/mytinytodo/remote/list.go new file mode 100644 index 0000000..8969930 --- /dev/null +++ b/mytinytodo/remote/list.go @@ -0,0 +1,11 @@ +package remote + +type loadListsResponse struct { + Total int `json:"total"` + Lists []List `json:"list"` +} + +type List struct { + ID string `json:"id"` + Name string `json:"name"` +} diff --git a/mytinytodo/remote/task.go b/mytinytodo/remote/task.go new file mode 100644 index 0000000..63bbc33 --- /dev/null +++ b/mytinytodo/remote/task.go @@ -0,0 +1,12 @@ +package remote + +type loadTasksResponse struct { + Total int `json:"total"` + Tasks []Task `json:"list"` +} + +type Task struct { + ID string `json:"id"` + Title string `json:"title"` + Complete int `json:"compl"` +} diff --git a/testdata/quick/build b/testdata/quick/build new file mode 100644 index 0000000..aea693e --- /dev/null +++ b/testdata/quick/build @@ -0,0 +1 @@ +qtdeploy test desktop ${PWD#${GOPATH}/src/} diff --git a/testdata/quick/main.go b/testdata/quick/main.go new file mode 100644 index 0000000..e4e12d5 --- /dev/null +++ b/testdata/quick/main.go @@ -0,0 +1,20 @@ +package main + +import ( + "os" + + "github.com/therecipe/qt/core" + "github.com/therecipe/qt/gui" + "github.com/therecipe/qt/qml" +) + +func main() { + core.QCoreApplication_SetAttribute(core.Qt__AA_EnableHighDpiScaling, true) + + gui.NewQGuiApplication(len(os.Args), os.Args) + + var app = qml.NewQQmlApplicationEngine(nil) + app.Load(core.NewQUrl3("qrc:/qml/application.qml", 0)) + + gui.QGuiApplication_Exec() +} diff --git a/testdata/quick/qml/application.qml b/testdata/quick/qml/application.qml new file mode 100644 index 0000000..af68251 --- /dev/null +++ b/testdata/quick/qml/application.qml @@ -0,0 +1,148 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//Slightly edited the original code for a scrollable TextArea and Qt Quick 2 controls + +import QtQuick 2.2 +import QtQuick.Controls 2.0 +import QtQuick.Layouts 1.3 + +ApplicationWindow { + visible: true + title: "Basic layouts" + property int margin: 11 + minimumWidth: 600 + minimumHeight: 450 + + ColumnLayout { + id: mainLayout + anchors.fill: parent + anchors.margins: margin + GroupBox { + id: rowBox + title: "Row layout" + Layout.fillWidth: true + + RowLayout { + id: rowLayout + anchors.fill: parent + TextField { + placeholderText: "This wants to grow horizontally" + Layout.fillWidth: true + } + Button { + text: "Button" + } + } + } + + GroupBox { + id: gridBox + title: "Grid layout" + Layout.fillWidth: true + + GridLayout { + id: gridLayout + rows: 3 + flow: GridLayout.TopToBottom + anchors.fill: parent + + Label { text: "Line 1" } + Label { text: "Line 2" } + Label { text: "Line 3" } + + TextField { } + TextField { id: textField } + TextField { } + + Flickable { + anchors { + top: parent.top + left: textField.right + right: parent.right + bottom: parent.bottom + } + + contentHeight: textid.width + contentWidth: textid.height + + TextArea.flickable: TextArea { + id: textid + text: "This widget spans over three rows in the GridLayout.\n" + + "All items in the GridLayout are implicitly positioned from top to bottom." + wrapMode: TextArea.Wrap + } + + ScrollBar.vertical: ScrollBar { } + } + } + } + TextArea { + id: t3 + text: "This fills the whole cell" + Layout.minimumHeight: 30 + Layout.fillHeight: true + Layout.fillWidth: true + } + GroupBox { + id: stackBox + title: "Stack layout" + implicitWidth: 200 + implicitHeight: 60 + Layout.fillWidth: true + Layout.fillHeight: true + StackLayout { + id: stackLayout + anchors.fill: parent + + function advance() { currentIndex = (currentIndex + 1) % count } + + Repeater { + id: stackRepeater + model: 5 + Rectangle { + color: Qt.hsla((0.5 + index)/stackRepeater.count, 0.3, 0.7, 1) + Button { anchors.centerIn: parent; text: "Page " + (index + 1); onClicked: { stackLayout.advance() } } + } + } + } + } + } +} \ No newline at end of file diff --git a/testdata/widget/build b/testdata/widget/build new file mode 100644 index 0000000..aea693e --- /dev/null +++ b/testdata/widget/build @@ -0,0 +1 @@ +qtdeploy test desktop ${PWD#${GOPATH}/src/} diff --git a/testdata/widget/main.go b/testdata/widget/main.go new file mode 100644 index 0000000..4939da4 --- /dev/null +++ b/testdata/widget/main.go @@ -0,0 +1,218 @@ +//source: http://doc.qt.io/qt-5/qtwidgets-widgets-lineedits-example.html + +package main + +import ( + "os" + + "github.com/therecipe/qt/core" + "github.com/therecipe/qt/gui" + "github.com/therecipe/qt/widgets" +) + +func main() { + widgets.NewQApplication(len(os.Args), os.Args) + + var ( + echoGroup = widgets.NewQGroupBox2("Echo", nil) + echoLabel = widgets.NewQLabel2("Mode:", nil, 0) + echoComboBox = widgets.NewQComboBox(nil) + echoLineEdit = widgets.NewQLineEdit(nil) + ) + echoComboBox.AddItems([]string{"Normal", "Password", "PasswordEchoOnEdit", "No Echo"}) + echoLineEdit.SetPlaceholderText("Placeholder Text") + + var ( + validatorGroup = widgets.NewQGroupBox2("Validator", nil) + validatorLabel = widgets.NewQLabel2("Type:", nil, 0) + validatorComboBox = widgets.NewQComboBox(nil) + validatorLineEdit = widgets.NewQLineEdit(nil) + ) + validatorComboBox.AddItems([]string{"No validator", "Integer validator", "Double validator"}) + validatorLineEdit.SetPlaceholderText("Placeholder Text") + + var ( + alignmentGroup = widgets.NewQGroupBox2("Alignment", nil) + alignmentLabel = widgets.NewQLabel2("Type:", nil, 0) + alignmentComboBox = widgets.NewQComboBox(nil) + alignmentLineEdit = widgets.NewQLineEdit(nil) + ) + alignmentComboBox.AddItems([]string{"Left", "Centered", "Right"}) + alignmentLineEdit.SetPlaceholderText("Placeholder Text") + + var ( + inputMaskGroup = widgets.NewQGroupBox2("Input mask", nil) + inputMaskLabel = widgets.NewQLabel2("Type:", nil, 0) + inputMaskComboBox = widgets.NewQComboBox(nil) + inputMaskLineEdit = widgets.NewQLineEdit(nil) + ) + inputMaskComboBox.AddItems([]string{"No mask", "Phone number", "ISO date", "License key"}) + inputMaskLineEdit.SetPlaceholderText("Placeholder Text") + + var ( + accessGroup = widgets.NewQGroupBox2("Access", nil) + accessLabel = widgets.NewQLabel2("Read-only:", nil, 0) + accessComboBox = widgets.NewQComboBox(nil) + accessLineEdit = widgets.NewQLineEdit(nil) + ) + accessComboBox.AddItems([]string{"False", "True"}) + accessLineEdit.SetPlaceholderText("Placeholder Text") + + echoComboBox.ConnectCurrentIndexChanged(func(index int) { echoChanged(echoLineEdit, index) }) + validatorComboBox.ConnectCurrentIndexChanged(func(index int) { validatorChanged(validatorLineEdit, index) }) + alignmentComboBox.ConnectCurrentIndexChanged(func(index int) { alignmentChanged(alignmentLineEdit, index) }) + inputMaskComboBox.ConnectCurrentIndexChanged(func(index int) { inputMaskChanged(inputMaskLineEdit, index) }) + accessComboBox.ConnectCurrentIndexChanged(func(index int) { accessChanged(accessLineEdit, index) }) + + var echoLayout = widgets.NewQGridLayout2() + echoLayout.AddWidget(echoLabel, 0, 0, 0) + echoLayout.AddWidget(echoComboBox, 0, 1, 0) + echoLayout.AddWidget3(echoLineEdit, 1, 0, 1, 2, 0) + echoGroup.SetLayout(echoLayout) + + var validatorLayout = widgets.NewQGridLayout2() + validatorLayout.AddWidget(validatorLabel, 0, 0, 0) + validatorLayout.AddWidget(validatorComboBox, 0, 1, 0) + validatorLayout.AddWidget3(validatorLineEdit, 1, 0, 1, 2, 0) + validatorGroup.SetLayout(validatorLayout) + + var alignmentLayout = widgets.NewQGridLayout2() + alignmentLayout.AddWidget(alignmentLabel, 0, 0, 0) + alignmentLayout.AddWidget(alignmentComboBox, 0, 1, 0) + alignmentLayout.AddWidget3(alignmentLineEdit, 1, 0, 1, 2, 0) + alignmentGroup.SetLayout(alignmentLayout) + + var inputMaskLayout = widgets.NewQGridLayout2() + inputMaskLayout.AddWidget(inputMaskLabel, 0, 0, 0) + inputMaskLayout.AddWidget(inputMaskComboBox, 0, 1, 0) + inputMaskLayout.AddWidget3(inputMaskLineEdit, 1, 0, 1, 2, 0) + inputMaskGroup.SetLayout(inputMaskLayout) + + var accessLayout = widgets.NewQGridLayout2() + accessLayout.AddWidget(accessLabel, 0, 0, 0) + accessLayout.AddWidget(accessComboBox, 0, 1, 0) + accessLayout.AddWidget3(accessLineEdit, 1, 0, 1, 2, 0) + accessGroup.SetLayout(accessLayout) + + var layout = widgets.NewQGridLayout2() + layout.AddWidget(echoGroup, 0, 0, 0) + layout.AddWidget(validatorGroup, 1, 0, 0) + layout.AddWidget(alignmentGroup, 2, 0, 0) + layout.AddWidget(inputMaskGroup, 0, 1, 0) + layout.AddWidget(accessGroup, 1, 1, 0) + + var window = widgets.NewQMainWindow(nil, 0) + window.SetWindowTitle("Line Edits") + + var centralWidget = widgets.NewQWidget(window, 0) + centralWidget.SetLayout(layout) + window.SetCentralWidget(centralWidget) + + window.Show() + + widgets.QApplication_Exec() +} + +func echoChanged(echoLineEdit *widgets.QLineEdit, index int) { + switch index { + case 0: + { + echoLineEdit.SetEchoMode(widgets.QLineEdit__Normal) + } + + case 1: + { + echoLineEdit.SetEchoMode(widgets.QLineEdit__Password) + } + + case 2: + { + echoLineEdit.SetEchoMode(widgets.QLineEdit__PasswordEchoOnEdit) + } + + case 3: + { + echoLineEdit.SetEchoMode(widgets.QLineEdit__NoEcho) + } + } +} + +func validatorChanged(validatorLineEdit *widgets.QLineEdit, index int) { + switch index { + case 0: + { + validatorLineEdit.SetValidator(nil) + } + + case 1: + { + validatorLineEdit.SetValidator(gui.NewQIntValidator(validatorLineEdit)) + } + + case 2: + { + validatorLineEdit.SetValidator(gui.NewQDoubleValidator2(-999.0, 999.0, 2, validatorLineEdit)) + } + } + + validatorLineEdit.Clear() +} + +func alignmentChanged(alignmentLineEdit *widgets.QLineEdit, index int) { + switch index { + case 0: + { + alignmentLineEdit.SetAlignment(core.Qt__AlignLeft) + } + + case 1: + { + alignmentLineEdit.SetAlignment(core.Qt__AlignCenter) + } + + case 2: + { + alignmentLineEdit.SetAlignment(core.Qt__AlignRight) + } + } +} + +func inputMaskChanged(inputMaskLineEdit *widgets.QLineEdit, index int) { + switch index { + case 0: + { + inputMaskLineEdit.SetInputMask("") + } + + case 1: + { + inputMaskLineEdit.SetInputMask("+99 99 99 99 99;_") + } + + case 2: + { + inputMaskLineEdit.SetInputMask("0000-00-00") + inputMaskLineEdit.SetText("00000000") + inputMaskLineEdit.SetCursorPosition(0) + } + + case 3: + { + inputMaskLineEdit.SetInputMask(">AAAAA-AAAAA-AAAAA-AAAAA-AAAAA;#") + } + } +} + +func accessChanged(accessLineEdit *widgets.QLineEdit, index int) { + switch index { + case 0: + { + accessLineEdit.SetReadOnly(false) + } + + case 1: + { + accessLineEdit.SetReadOnly(true) + } + } +} \ No newline at end of file