Урок 20. Пользовательские настройки

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

Начнем с настройки прав доступа к новой функциональности.

Права доступа

Перейдем в файл описания работы серверной части приложения (Template.xml) .

Добавим точку доступа UserSettingsEditAccessPoint для просмотра и редактирования пользовательских настроек.

Создадим разрешение UserSettingsPermission, в которое добавим эту точку доступа. Добавим это разрешение в таблицу template.permission и настроим права доступа для пользовательских групп:

INSERT INTO template.permission_block_item(permission_block_id, id_title, title)
SELECT
  PB.permission_block_id, 'user_settings', 'Пользовательские настройки'
FROM
  template.permission_block PB
WHERE
  PB.id_title = 'user_action'
ON CONFLICT (id_title) DO NOTHING;

INSERT INTO template.permission(name, permission_block_item_id)
SELECT
  'UserSettingsPermission', PBI.permission_block_item_id
FROM
  template.permission_block_item PBI
WHERE
  PBI.id_title = 'user_settings'
ON CONFLICT (name) DO NOTHING;

INSERT INTO template.group_permission(group_id, permission_id)
SELECT
  group_id,
  permission_id
FROM
  template.permission P,
  template."group" G
WHERE
  (G.name = 'AdministratorGroup' OR G.name ISNULL) AND
  P.name = 'UserSettingsPermission'
ON CONFLICT (group_id, permission_id) DO NOTHING;

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

Часовой пояс

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

В приложении "Временные зоны" собрана полная информация о работе с датами со временем в платформе WT.

Форма

Создайте форму для редактирования пользовательских настроек (TemplateUserSettings.xml):

На главной форме (TemplateStart.xml) в меню добавьте пункт Опции -> Пользовательские настройки..., по которому будет открываться новая форма. Не забудьте использовать UserSettingsEditAccessPoint, чтобы ограничить доступ к пункту меню.

Запросы

Добавим запрос на получение списка часовых поясов:

Добавим запросы на чтение и изменение значения пользовательской временной зоны:

Добавьте три новых запроса в UserSettingsPermission.

Формы

Если пользователь изменил свой часовой пояс в настройках, то необходимо перезапустить приложение, чтобы новые настройки применились.

Добавим условие проверки изменения часового пояса:

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

Скорректируем команду SaveSequentialCommand:

Запустите приложение и проверьте смену часового пояса.

Мультиязычность

Помимо выбора собственной часовой зоны пользователь может настраивать язык интерфейса своей клиентской части.

Настройка языка

Переделайте форму пользовательских настроек, добавив выпадающий список "Язык":

Добавим запрос на получения списка поддерживаемых языков:

Не забудьте добавить этот запрос в UserSettingsPermission.

В запросы UserSettingsSelectSqlQuery и UserSettingsUpdateSqlQuery добавим поле LanguageId:

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

Заменим параметр Updated на параметр LanguageUpdated - так будет более наглядно:

Скорректируйте команду типа ValueSetCommand, которая будет присваивать этому параметру значение True, если значение языка изменилось.

Добавим условие проверки изменения зыка:

Скорректируем команду SaveSequentialCommand:

Изменение языка приложения

Скорректируем представление template.user_info, расширив его новыми полями language_id и language_code:

В серверном xml-файле скорректируем запрос UserCurrentSelectSqlQuery, добавив поле LanguageCode:

Перейдем в файл стартовой формы и в UserCurrentPrimaryGetDataConnection добавим новое поле LanguageCode:

Создадим команду обновления для UserCurrentPrimaryGetDataConnection, удалив его из команды AllPrimaryGetDataConnectionRefreshCommand:

Создадим команду типа LocaleSetCommand, с помощью которой будем устанавливать локаль и язык перевода для всего приложения:

Соберем обе команды в одну последовательность:

Добавим Execution на параметр LanguageUpdated команды UserSettingsFormShowCommand:

Добавим вызов команды LocaleSequentialCommand в Execution, которые срабатывают на команды LoginFormShowCommand и ReloginFormShowCommand - тем самым мы будем задавать настройки текущего пользователя при его аутентификации в программе.

Доработка форм

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

Файлы строковых ресурсов

Скачайте архив с файлами строковых ресурсов и распакуйте его в папку с формами проекта (\Template\Projects\1. Template\Forms).

5KB
Open

В папке Language вы найдете файлы:

По договоренности внутри компании: файлы ru.wxlf и en.wxlf используем для задания строковых ресурсов для форм, а файлы object-ru.wxlf и object-en.wxlf - для кастомных элементов (команд, объектов и т.д.), которые рассмотрим в одном из следующих уроков. На самом деле платформа считывает из папки Forms\Language все файлы одной локали и записывает их в один словарь. И файлов по одной локали может быть сколько угодно - отбор происходит по имени файла, оно должно оканчиваться именем локали (ru/en).

Структура файлов одинакова:

Тэг <Wxliff> содержит список вложенных тэгов <Context>. Каждый такой тэг привязывается к конкретному файлу, имя которого указывается в атрибуте File. Если атрибут отсутствует, то такой контекст считается общим для всех форм.

Каждый контекст содержит набор строковых ресурсов, представленных тэгом <Text>, у которого есть атрибуты:

  • Id - уникальный (в рамках контекста) идентификатор ресурса, по которому форма будет его искать. Обязательный атрибут.

Тэг <Text> содержит тэги:

  • <Source> - оригинальный текст, который выступает в качестве подсказки в файле перевода. Необязательный тэг;

  • <Target> - целевая строка, которая будет использоваться на форме.

В файлах ru.wxlf и en.wxlf есть начальные данные, и указаны два тэга <Context>: общий контекст с ресурсами, которые используются на многих формах, и контекст для формы TemplateUserSettings.xml.

Использование строкового ресурса на форме

Давайте перейдем в файл формы пользовательских настроек (TemplateUserSettings.xml) и на его примере разберем использование строковых ресурсов.

В файле формы необходимо все строковые константы заменить тэгом <Text>, значением которого будет строка:

Например, на форме есть параметр Title:

Заменим его описание:

В файлах ru.wxlf и en.wxlf в соответствующем контексте есть строковые ресурсы:

Замените текст объектов LanguageLabel и TimeZoneInfoLabel, используя идентификатор строковых ресурсов из контекста данной формы.

А для текста кнопки SaveButton используйте идентификатор строкового ресурса из общего контекста:

Запустите приложение и проверьте смену языка.

Как это работает

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

Сначала форма ищет в общем контексте, если там нет нужного ресурса, то продолжает искать в собственном контексте.

Когда форма находит подходящий ресурс, то берет из него значение тэга <Target> и использует это значение в своих элементах.

Если форма не находит подходящего ресурса в файле строковых ресурсов, то использует текст, который указали в качестве значения тэга <Text>.

Другие замены

Продолжим работать с формой пользовательских настроек (TemplateUserSettings.xml).

На форме есть команды SaveOnCloseMessageBoxCommand и CloseOnCloseMessageBoxCommand - в них тоже необходимо подобным образом заменить значения тэгов <Caption> и <Text>:

Аналогичным образом сделайте с командой UserTimeZoneInfoChangedMessageBoxCommand.

Замена констант

На самом деле подобные подстановки ресурсов мы можем делать с любыми константами на форме.

В качестве примера мы можем привязать ширину кнопки SaveButton к локали.

Добавим в файлы строковых ресурсов значения:

Запустите приложение и проверьте отображение кнопки при использовании разных языков:

Эти изменения можно убрать - они носили демонстрационный характер.

ComboBox

Перейдем в файл карточки назначения платежа (TemplateOperationEdit.xml) и найдем там описание объекта CategoryComboBox.

В объекте используется вложенный тэг <NullValue> для настройки отображения NULL-значения выпадающего списка:

Использование атрибута Title в тэге <NullValue>не позволяет заменять его значение на строковый ресурс. Поэтому заменим атрибут Title на тэг <NullValueTitle>. Это позволит динамически задавать отображение NULL-значения объекта, в том числе для поддержки мультиязычности.

В файлах строковых ресурсов в общем контексте уже есть нужное значение. Его и будем использовать:

На некоторых формах у нас есть фильтр архивных актуальных записей (ArchiveFilterComboBox):

При поддержке мультиязычности он примет вид:

Поддержка языков в SQL-запросах

В некоторых запросах мы уже сталкивались с функцией public.string_value(character varying, integer), которая относительно настроек языка пользователя возвращала по ключу из таблицы public.strings соответствующую строку.

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

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

В своей практике мы используем функцию public.check_strings(), которая проверяет наличие переводов для всех языков и вернет список ключей, у которых отсутствует перевод для какого-либо языка.

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

Самостоятельно

Переведите все формы на поддержку языков.

Не забудьте перевести строковые константы в запросах для списка назначений платежей и отчета по бюджету. Добавьте строковые ресурсы в таблицу public.strings и используйте функцию public.string_value(character varying, integer) для получения нужного значения, как это сделано в запросе TimeZoneInfoSelectSqlQuery и LoadModeSelectSqlQuery.

Также добавьте перевод для описания динамических прав доступа - запрос PermissionBlockItemSelectSqlQuery. Используйте значения в колонках id_title таблиц template.permission_block и template.permission_block_item в качестве ключа для строковых ресурсов.

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

Пользовательские настройки форм

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

Все это можно сохранять для каждого пользователя отдельно.

Настройки таблиц

Для сохранения настроек в таблице DatabaseTable реализован вложенный тэг <SaveOnFormClose>:

Информация о настройках пишется в таблицу public.user_form_info. Для каждой формы и каждого пользователя отдельная запись.

Давайте перейдем в файл списка клиентов (TemplateClientList.xml) и в таблицу ClientDatabaseTable добавим тэг <SaveOnFormClose>.

Когда откроем и закроем окно списка клиентов, в базе данных в таблице появится запись:

Значение в колонке name совпадает со значение в атрибуте Name тэга <Form>.

Так как мы просто открыли и закрыли форму, то в колонке tables_info хранится информация только о колонках:

Чтобы можно было менять размер колонок, необходимо в таблице атрибуту Value тэга <AllowResizeColumns> поставить значение True, а для колонки атрибуту Value тэга <AutoSizeMode> поставить значение None.

Давайте это сделаем для колонки CityTitle (Город). Откроем форму списка клиентов, изменим ширину колонки "Город" и закроем окно. При повторном открытии формы мы увидим, что размер колонки сохранился, а в базе будет запись вида:

Добавим настраиваемый фильтр в таблицу через контекстное меню, кликнув ПКМ по заголовку таблицы:

В таблицу сохранится запись вида:

Давайте сбросим фильтрацию и добавим настраиваемую сортировку:

Теперь в таблицу сохранится запись вида:

Состояние формы

Чтобы сохранять состояние формы, у тэга <Form> есть атрибут RestoreLastFormState. Если значение атрибута равно True, то состояние формы будет запоминаться в колонку form_state таблицы public.user_form_info.

Поддерживается три состояния:

  • 0 - окно с размерами по умолчанию (Normal);

  • 1 - свернутое окно (Minimized);

  • 2 - развернутое окно (Maximized).

Значение Variable

Для сохранения значения переменной Variable реализован вложенный тэг <SaveOnFormClose>:

Значения переменных сохраняются в колонку variables_info таблицы public.user_form_info.

На форме списка клиентов создайте тестовую переменную, которой укажите тэг <SaveOnFormClose> со значением True и каким-нибудь значением. Откройте и закройте форму списка, а затем проверьте содержимое таблицы public.user_form_info.

Итоги

В этом уроке мы познакомились с поддержкой языков в платформе WT и реализовали пользовательские настройки. Узнали, что на формах можно сохранять настройки видимости, ширину и порядок столбцов таблицы, фильтры и сортировку строк в DatabaseTable, а также состояние самой формы.

Ответы

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

587KB
Open

Last updated