Faist

JavaScript Frameworks по-русски

Установка Linux Debian в VirtualBox

Установка VirtualBox

Тут все просто.

Скачиваем VirtualBox со страницы разработчика.

Запускаем установку и, в процессе установки, со всем соглашаемся.

Получение образа Debian

Идем на сайт https://www.debian.org/distrib/, выбираем небольшой установочный образ. В нашем случае выбираем iso-образы netinst для 64-битных ПК.

clip_image008

Пока образ качается, создаем новую виртуальную машину в VirtualBox.

Создание виртуальной машины

Перед созданием виртуальной машины необходимо включить в BIOS виртуализацию на вашем ПК (если она поддерживается). Иначе вам не удастся создать 64-битную виртуальную машину.

Запускаем VirtualBox.

После успешного запуска нажимаем кнопку “Создать”, вводим имя машины и пр.

clip_image001

В следующем диалоге задаем размер памяти для виртуальной машины.

clip_image002

Размер памяти можно потом изменить.

Далее создаем виртуальный жесткий диск. 

clip_image003

clip_image004

Нам важно создать “Фиксированный виртуальный жесткий диск” для повышения быстродействия виртуальной машины. Поэтому нажимаем кнопку «Скрыть подробности» (это такой перевод – возможно в вашей версии будет “Показать подробности”).

clip_image005

Установим переключатель в положение “Фиксированный виртуальный жесткий диск” и нажмем кнопку “Создать”.

clip_image006

Пока машина создается, у нас загрузился iso с Debian.

clip_image010

Все готово к установке.

Установка Debian

Запускаем Virtualbox, (если вы его уже закрыли) переходим на запись DebianTest (созданную по выше описанным инструкциям) и нажимаем кнопку «Настроить».

clip_image012

Переходим на вкладку «Носители». Выбираем «Контролер: IDE \ Пусто». Затем выбираем кнопку рядом с кнопкой «Вторичный мастер IDE».

clip_image014

clip_image016

Выбираем скачанный файл в качестве образа.

Все готово для установки.

Запускаем виртуальную машину.

Далее идут подряд экраны с небольшими комментариями.

Первый экран.

clip_image017

Выбираем Install, нажимаем Enter.

На следующем экране выбираем язык, который будет использоваться в процессе установки. Подтверждаем выбор клавишей Enter.

clip_image019

Выбираем язык Russian.

Затем выбираем местоположение и пр.

clip_image021

clip_image023

clip_image025

Производится загрузка дополнительных компонентов, определение оборудования.

Затем снова диалоги.

clip_image027

clip_image029

clip_image031

clip_image033

clip_image035

clip_image037

clip_image039

clip_image041

clip_image043

Далее загружаются дополнительные компоненты (пару секунд) .

И вот важный момент – разбиение диска. Нам нужно разбить его на два первичных раздела: раздел подкачки (0.5 Гбайт) и корневой раздел  (точка монтирования – "/");

Поэтому на следующем экране выбираем “Вручную”. Далее по картинкам.

clip_image045

Выбираем наш диск

clip_image047

clip_image049

clip_image051

clip_image053

clip_image055

clip_image057

clip_image059

В следующем экране нужно нажать “Enter” для смены типа файловой системы диска.

clip_image061

clip_image063

clip_image065

clip_image067

clip_image069

clip_image071

clip_image073

clip_image075

clip_image077

clip_image079

clip_image081

Далее идет установка базовой системы.

clip_image083

Выбираем источник дистрибутивов.

clip_image085

clip_image087

clip_image089

Поехали.

clip_image091

Важный запрос.

clip_image093

Добрались до главного – что мы хотим установить.

clip_image095

Далее самый длительный процесс установки ПО.

………………………………….

После этого запрос об установке загрузчика.

clip_image097

Еще чуть-чуть и…

clip_image099

Перегружаем и видим запрос на регистрацию пользователя.

clip_image101

Все, система установлена, софт VirtualBox «Дополнения для гостевой ОС» ставить не надо, все уже работает.

Qooxdoo часть 10.1 Диалог редактирования данных о пользователях

Продолжаем работу над задачей, сформулированной в предыдущей статье.

Реализация функций редактирования данных

Переходим к добавлению и редактированию данных. В этих случаях должен выводиться один и тот же диалог с полями для редактирования и кнопками «Save» и «Cancel». По кнопке «Save» данные должны передаваться классу бизнес-логики, который далее должен вставить данные в таблицу postgres. Как говорится: слон большой, мы будем есть его по частям, поэтому сначала реализуем диалог редактирования данных, затем класс бизнес-логики, который будет что-то делать с данными (добавлять, обновлять), которые мы затем передадим в таблицу.

Диалог редактирования данных о пользователе

Создаем окно

Мы должны создать окно с формой для редактирования данных о пользователе и с нужными кнопками. Подобные диалоги мы уже создавали в учебном приложении для twitter. Я буду использовать некоторую информацию из предыдущих статей.

Итак, создадим новый класс окна UIWindow, добавим в него форму, разместим в ней нужные элементы управления

qx.Class.define("users.UIWindow", 
{ 
extend : qx.ui.window.Window,
construct : function()
{
this.base(arguments, this.tr("User info"));
}
});

Создаваемое окно будет содержать только одну форму, которая сама позаботится о своем форматировании. Поэтому для самого окна базового форматирования будет достаточно. Мы также сделаем окно модальным.

//Добавим разметку
var layout = new qx.ui.layout.Basic();
this.setLayout(layout);
this.setModal(true);

Добавляем форму

Теперь пришло время вставить в окно форму с нужными полями для ввода данных.

//Добавляем поля
var usrId = new qx.ui.form.TextField();
usrId.setReadOnly(true);
this.__form.add(usrId, this.tr("ID"), null, "Id");
var usrSurname = new qx.ui.form.TextField();
usrSurname.setRequired(true);
this.__form.add(usrSurname, this.tr("Surname"), null, "Surname");
var usrName = new qx.ui.form.TextField();
usrName.setRequired(true);
this.__form.add(usrName, this.tr("Name"), null, "Name");
var usrPatronymic = new qx.ui.form.TextField();
this.__form.add(usrPatronymic, this.tr("Patronymic"), null, "Patronymic");
var usrTelephone = new qx.ui.form.TextField();
this.__form.add(usrTelephone, this.tr("Telephone"), null, "Telephone");
var usrLogin = new qx.ui.form.TextField();
usrLogin.setRequired(true);
this.__form.add(usrLogin, this.tr("Login"), null, "Login");
var usrPassword = new qx.ui.form.PasswordField();
usrPassword.setRequired(true);
this.__form.add(usrPassword, this.tr("Password"), null, "Password");
var usrNote = new qx.ui.form.TextArea();
this.__form.add(usrNote, this.tr("Note"), null, "Note");

Переменную формы мы сделали приватным (два подчеркивания перед именем) членом класса потому, что будем обращаться к ней за пределами конструктора.

Первое текстовое поле мы сделали только для чтения. Это поле мы никогда не будем менять сами, оно носит информационный характер и используется как ключевое в базе данных.

Обратите внимание на то, что некоторые поля помечены как обязательные для ввода. Например: usrSurname.setRequired(true). Рядом с такими полями будет отображаться звездочка. Обязательность заполнения поля позволит нам проводить простую проверку ввода данных.

Рассмотрим подробнее параметры метода add для формы. Первый параметр – переменная, указывающая на объект, который может быть на форме (текстовое поле, поле ввода пароля). Второй параметр – надпись у этого элемента, её мы обертываем функцией this.tr() для дальнейшего перевода. Третий параметр – функция проверки данных, в данном случае мы её не используем потому, что используем пометку обязательных для заполнения полей. Четвертый параметр – название для создания переменной, которая будет связана со значением поля. Диспетчер создаст для этих переменных функции доступа (get, set).

Свяжем данные с формой. Используем контроллер (диспетчер) данных.

var controller = new qx.data.controller.Form(null, this.__form);
this.__model = controller.createModel();

Точно также как в предыдущих случаях, мы создаем контроллер без модели. Затем мы просим контроллер создать модель для элементов формы. Эту модель мы будем использовать для сериализации данных формы.

Для формы также нужны кнопки «Save» для отправки данных на сервер и «Cancel» для закрытия окна. Добавляем кнопки.

//Добавим кнопки
var savebutton = new qx.ui.form.Button(this.tr("Save"));
this.__form.addButton(savebutton);
var cancelbutton = new qx.ui.form.Button(this.tr("Cancel"));
this.__form.addButton(cancelbutton);
cancelbutton.addListener("execute", function() {
this.close();
}, this);

Вот и все элементы, которые нам нужны, давайте отобразим их. Мы позволим встроенному в qooxdoo классу form.renderer позаботиться о размещении элементов на форме.

var renderer = new qx.ui.form.renderer.Single(form);
this.add(renderer);

Доступ к значениям формы

Подобно тому, как это сделано в MainWindow, мы будем использовать в новом окне события, чтобы сообщить другим частям нашего приложения об изменениях значений элементов формы. Как вы помните, блок кода «event» находится на том же уровне, что и блок кода конструктора.

events : {
"changeUserData" : "qx.event.type.Data"
},

Добавим обработчик кнопки «Save», который передаст данные из объекта model с проверкой данных в обработчик события изменения данных.

savebutton.addListener("execute", function() {
if(this.__form.validate()) {
var usrData = qx.util.Serializer.toJson(this.__model);
this.fireDataEvent("changeUserData", usrData);
this.close();
};
}, this);

Для проверки формы в класс Application добавим код создания формы.

this.__uiWindow = new twitter.UIWindow();
this.__uiWindow.moveTo(320,30);
this.__uiWindow.open();
И код обработчика события сохранения данных формы.
this.__uiWindow.addListener("changeUserData", function(e) {
this.debug("ChangeUserData: " + e.getData);
});

Сгенерируем приложение и откроем его в браузере. Форма ввода данных появляется при старте приложения.

Перевод интерфейса на русский язык

Для удобной дальнейшей работы переведем все на русский язык. Мы не забывали везде вставлять код this.tr() для названий, поэтому в переводе будем использовать возможности qooxdoo.

Сначала сообщим qooxdoo о том, что мы будем использовать еще и русский язык. Откройте в редакторе файл config.json и добавьте «ru» в строку "LOCALES" .

"LOCALES" : [ "en", "ru" ],

Затем запустим генератор с параметром translation.

./generate.py translation

После генерации в папке translation проекта отредактируйте файл ru.po.

Подробности мы уже рассматривали в одной из предыдущих статей.

Вот как примерно будет выглядеть ваш файл:

#
msgid ""
msgstr ""
"Project-Id-Version: 1.0\n"
"Report-Msgid-Bugs-To: you@your.org\n"
"POT-Creation-Date: 2011-01-12 19:36+0600\n"
"PO-Revision-Date: 2011-01-12 19:36+0600\n"
"Last-Translator: you <you@your.org>\n"
"Language-Team: Team <yourteam@your.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: users/Application.js:84
msgid "To remove records about user "
msgstr "Удалить данные о пользователе "
#: users/MUserInteraction.js:25 users/MUserInteraction.js:56
#: users/MUserInteraction.js:95 users/MUserInteraction.js:204
#: users/MUserInteraction.js:284
msgid "OK"
msgstr "Да"
#: users/UIWindow.js:59
msgid "Cancel"
msgstr "Выход"
#: users/MainWindow.js:6
msgid " The information on users"
msgstr "Информация о пользователях"
#: users/MainWindow.js:21
msgid "Add"
msgstr "Новый"
#: users/MainWindow.js:22
msgid "Add the information on the new user."
msgstr "Добавить информацию о новом пользователе"
#: users/MainWindow.js:28
msgid "Edit"
msgstr "Изменить"
#: users/MainWindow.js:29
msgid "Edit the information on the chosen user."
msgstr "Изменить информацию выбранного пользователя"
#: users/MainWindow.js:36
msgid "Delete"
msgstr "Удалить"
#: users/MainWindow.js:37
msgid "Delete the information on the chosen user."
msgstr "Удалить информацию о выбранном пользователе"
#: users/MainWindow.js:45 users/UIWindow.js:16
msgid "ID"
msgstr "№"
#: users/MainWindow.js:45 users/UIWindow.js:19
msgid "Surname"
msgstr "Фамилия"
#: users/MainWindow.js:45 users/UIWindow.js:22
msgid "Name"
msgstr "Имя"
#: users/MainWindow.js:46 users/UIWindow.js:24
msgid "Patronymic"
msgstr "Отчество"
#: users/MainWindow.js:46 users/UIWindow.js:26
msgid "Telephone"
msgstr "Телефон"
#: users/MainWindow.js:46 users/UIWindow.js:29
msgid "Login"
msgstr "Логин"
#: users/MainWindow.js:47 users/UIWindow.js:32
msgid "Password"
msgstr "Пароль"
#: users/MainWindow.js:47 users/UIWindow.js:34
msgid "Note"
msgstr "Примечание"
#: users/UIWindow.js:6
msgid "User info"
msgstr "Информация о пользователе"
#: users/UIWindow.js:39
msgid "Save"
msgstr "Сохранить"

После редактирования снова сгенерируйте приложение generate.py source и откройте его в браузере.

 

Table1

Как видим, интерфейс русский, обязательные поля помечены звездочкой. Убедитесь, что кнопки работают.

Связывание значений из таблицы с диалогом редактирования

Форма редактирования должна вызываться по кнопкам Новый и Изменить (в русском интерфейсе). При этом в случае изменения данных, в форму нужно передать значения из текущей строки таблицы.

Для реализации этого нам нужно создавать окно диалога в момент вызова обработчиков главного окна.

Мы поступим следующим образом: создадим объект диалога при старте приложения и будем отображать его при необходимости, заполняя или очищая в нем поля.

Уберите следующую строку кода из Application.js.

this.__uiWindow.open();

И перепишите обработчики событий NewUser и EditUser.

mainWnd.addListener("NewUser", function() {
this.debug("NewUser");
this.__uiWindow.setData(null);
this.__uiWindow.open();
}, this);
mainWnd.addListener("EditUser", function(e) {
this.debug("EditUser: " + e.getData());
this.__uiWindow.setData(e.getData());
this.__uiWindow.open();
}, this);

Заметили? Мы вызываем несуществующий метод диалога редактирования setData() для передачи в него некоторых данных.

Давайте реализуем этот метод в файле UIWindow.js.

Для этого добавим в него блок members (я вставил его перед блоком events).

members : {
setData : function (aUsrInfo){
if(aUsrInfo == null) {
this.__form.reset();
}
else if(aUsrInfo.length > 7)
{
this.__model.setId(aUsrInfo[0].toString());
this.__model.setSurname(aUsrInfo[1]);
this.__model.setName(aUsrInfo[2]);
this.__model.setPatronymic(aUsrInfo[3]);
this.__model.setTelephone(aUsrInfo[4]);
this.__model.setLogin(aUsrInfo[5]);
this.__model.setPassword(aUsrInfo[6]);
this.__model.setNote(aUsrInfo[7]);
}
}
},

В этом блоке я реализовал метод setData со следующей логикой: если переданный параметр == null, то я очищаю все поля формы, иначе я проверяю длину переданного массива данных и заполняю переменные модели нужными значениями.

Недостаток этого кода очевиден: мы изначально предполагаем, что данные в массиве расположены в нужном нам порядке, тем самым создавая тесную связь между разными частями кода. Это проходит в учебном примере, но для реальных задач нужно придумать что-нибудь более типизированное.

Но давайте убедимся, что все работает. Сгенерируйте и запустите приложение.

Выберите строку в таблице и нажмите кнопку изменить. Убедитесь, что все работает.

Table2

Попутно замечу, что мы не внесли ни одного изменения в файл MainWindow.js, поскольку использовали идею разделения кода по классам. Закройте диалог ввода информации и нажмите кнопку Новый.

Table1

Вы заметили, что у нас не так? Правильно: кнопка Сохранить активна, хотя поля пусты, а это противоречит нашему плану. И хотя сохранение не будет, пока не заполнены обязательные поля, все же активная кнопка может ввести пользователя в заблуждение. Исправим эту ситуацию.

Мы создадим у класса окна диалога метод onChange() и будем вызывать его при изменениях в полях формы. Метод onChange() будет вызывать функцию проверки формы и в зависимости от этого включать или отключать кнопку. Чтобы в методе увидеть кнопку, сделаем ее членом класса окна.

Итак, сначала заменим

var savebutton = new qx.ui.form.Button(this.tr("Save"));

на

this.__savebutton = new qx.ui.form.Button(this.tr("Save"));

И, соответственно, все вхождения savebutton на this.__savebutton.

Далее создадим метод окна onChange() в блоке members. Этот метод не должен быть виден за пределами класса, поэтому сделаем его приватным.

__onChange : function(){
this.__savebutton.setEnabled(this.__form.validate());
}

Если вы вставили этот метод в конец блока members, не забудьте поставить перед ним запятую, иначе – поставьте запятую после метода.

А теперь для каждого поля формы, кроме id, нужно написать обработчик похожий на следующий.

usrSurname.addListener("input", function(e) {
this.__onChange();
}, this);

Осталось сделать кнопку Save по умолчанию недоступной. Мы сделаем это в начале метода setData, поскольку при открытии окна диалога без внесения изменений сохранять нечего.

this.__savebutton.setEnabled(false);

Снова запустите приложение и убедитесь, что кнопка Save ведёт себя как надо.

Table3

Мы закончили работу с интерфейсом, в следующей статье перейдем к реализации логики в отдельном классе для взаимодействия с базой данных.