Zeta 1.1, 1.6 Documentation (проект Zeta НЕФОРМАЛЬНАЯ документация) Update 2009: Создана версия для JRE 1.6 (см. добавления в конце) Текущие версии документации и программных модулей находятся в системе контроля версий SVN: http://zeta-cis.no-ip.org/svn/zeta_doc/ , логин/пароль test/test Общие представления Язык разметки интерфейсов Макроподстановки и Zeta Script Введение Справочник Построение новых конструкций (Java) Распространенные ситуации и маленькие секреты Настройка системы Вопросы,примеры,известные баги o o o o Данная система является мультиплатформенной средой для создания клиентских интерфейсов к базам данных. Реализована эта среда на Java и поэтому теоретически работает на любой платформе, под которую реализована JVM. В данной документации приводятся примеры работы и настройки системы с СУБД Postgres 6.5 Общие представления Задача решаемая данной системой - представление данных базы для пользователя в приемлемом виде и возможность создавать/изменять/удалять данные. Например, бухгалтер работает с приходными и расходными счет фактурами, тогда ему желательно видеть эти документы в виде максимально приближенном к реальному. Для построения таких форм служит язык разметки интерфейсов RML. Но кроме предоставления доступа к данным через некоторую форму требуется реализовывать некоторые процедурные расширения. Например, проверку на правильность введенных значений, в простейшем случае, или поддерживать функциональность сложного иерархического справочника, в более сложном. Для этих целей служат макроподстановки и Script. В системе как бы существует два слоя, несущих различную функциональную нагрузку. Слой представления базы на клиенте (DATASTORE) и слой визуальных компонентов - форм которые видит и с которыми работает пользователь. В DATASTORE описываются представления таблиц базы, и правила сохранения измененных данных. Напротив, в визуальных компонентах указано, в какой DATASTORE хранится редактируемая ими информация и как ее отображать. Язык разметки интерфейсов. Для описания интерфейса документа (далее просто документа) используется структурный язык разметки следующего вида KOI8_R DOCUMENT {FORM LEFT=1 RIGHT=1 WIDTH=200 HEIGHT=200 {FIELD ALIAS=FLD1 LEFT=10 TOP=10 WIDTH=100 HEIGHT=50 TARGET=A} {FIELD ALIAS=FLD2 LEFT=10 TOP=100 WIDTH=100 HEIGHT=50 TARGET=B} {DATASTORE ALIAS=DS QUERY="select 'alfa'::varchar as a, 'beta'::varchar as b from dual"} } При открытии такого документа мы увидим два редактируемых поля, в первом будет текст alfa а во втором beta. Теперь посмотрим, из чего состоит описание документа. Первая строчка - это кодировка, в которой написан документ, вторая - тип документа (пока ни какого значения не имеет но необходима), дальше идет иерархическое описание документа. В документе на верхнем уровне находится форма компонент FORM. У формы заданы размеры, местоположение и алиас, который позволяет обращаться к одному компоненту из другого. В форме определены два поля и DATASTORE, которая содержит две колонки а и b, которые являются результатом запроса к базе. В полях редактирования FLD1 и FLD2 в атрибуте TARGET указано, из какого столбца строки результата запроса надо брать данные. А вот более сложный, но интересный пример. Напишем документ, позволяющий выдавать любые запросы к базе и просматривать результат запроса. KOI8_R DOCUMENT {SPLITPANEL PERCENT = 30 TYPE = "HORIZONTAL" {EDITOR ALIAS = "ED" FOREGROUND = "black" BACKGROUND = "white" EXP = "($try ( ($DS@setsql ($ed@gettext)) ($grid@retrieve)) $catch ('ANY') ())" MULTIWINDOW = "YES" FONT = "Courier,PLAIN,14" } {GRID BUTTONBAR_FONT = "Courier,PLAIN,8" ROWSIZE = 16 TITLEBAR_FONT = "Courier,PLAIN,8" ALIAS = "grid" FOREGROUND = "black" BACKGROUND = "white" FONT = "Times,PLAIN,12" TITLEBAR_SIZE = 10 {DATASTORE QUERY = "select 'empty'::varchar as empty from dual" ALIAS = "DS" } } } Здесь пространство документа разделено на две части: в верхней находится редактор, в котором можно набирать SQL запрос, а в нижней таблица с результатом запроса. При выполнении запросов изменяется структура таблицы. Запросы выполняются через всплывающее меню компонента EDITOR через пункт выполнить. Этот пункт запускает на выполнение скрипт, написанный в атрибуте EXP, который устанавливает в DATATASTORE новый запрос и вызывает команду перезачитывания данных, в результате чего DATASTORE, а соответственно и таблица, содержат данные указанного запроса. Вообще документ может содержать следующие компоненты Справочник RML Типичные выражения <action> <command> <command> <command> <args> <args> <args> <args> <operation> <op> <expression> <charset> <container> <color> "<command>;<command>;..." open[new][over] Doc.rml [<args>] create[new][over] Doc.rml [<args>] retrieve alias <string>,[<args>] <int>,[<args>] <ident>,[<args>] ~alias~,[<args>] "<op>;<op>;..." alias=<expression> as is (Zeta SCRIPT) {CP1251,KOI8_R,CP866,ISO8859_5,...} {FORM,SCROLLPANE,SPLITPANEL} {#RGB, #RRGGBB, white, black, lightgray, gray, blue, red, green, yellow} Объекты RML. BUTTON CHART CHECKBOX CHECKGROUP COLONTITUL COLUMN DATASTORE DSCOLLECTION EDITOR FIELD FORM GRID GROSSTAB GROUP GROUPREPORT ITEM LABEL LINE MENU RADIOBUTTON RADIOGROUP REPORT REPORTGRID REPORTHEADER REPORTTRAILER SCROLPANEL Кнопка График Переключатель Группа переключателей Колонтитул отчета Столбец таблицы Объект читающий/пишущий из базы данных, а также хранящий выборку Объект, собирающий Datastore, и обеспечивающий все действия в базе в пределах одной транзакции. Многострочный редактор с возможностью добавления закладок Редактируемое поле формы Форма ввода Таблица Объект, потомок Datastore, на основе исходного двумерного массива строит GrossTab Объект, задающий группировку в отчетах Объект, потомок Datastore, отличается от нее тем, что хранит не двумерный массив, а дерево Элемент меню Нередактируемое поле формы Линия в отчете Всплывающее меню Переключатель Группа переключателей Объект - отчет Таблица отчета Заголовок группы отчета Trailer группы отчета Контейнер, обеспечивающий прокрутку (скроллинг) SPLITPANEL TABSET TOOLBAR TREEVIEW TVNAV помещенного в него компонента Контейнер, делящий свое пространство на две части по горизонтали или по вертикали Объект-контейнер с закладками Объект содержащий в себе кнопки Дерево Специальный объект Отношения объектов RML Компонент BUTTON CHART CHECKBOX CHECKGROUP COLONTITUL COLUMN DATASTORE DSCOLLECTION EDITOR FIELD FORM GRID GROSSTAB GROUP GROUPREPORT ITEM LABEL LINE MENU RADIOBUTTON RADIOGROUP REPORT REPORTGRID REPORTHEADER REPORTTRAILER SCROLPANEL SPLITPANEL TABSET TOOLBAR TREEVIEW DEFAULT SECTION {Cp1251,KOI8-R, } DOC Может содержать Ничего DATASTORE Ничего CHECKBOX FIELD, LABEL DATASTORE DATASTORE, GROUPREPORT Ничего Ничего Ничего FIELD, DATASTORE, MENU, RADIOGROUP, CHECKGROUP, LABEL, BUTTON COLUMN, DATASTORE, MENU DATASTORE REPORTHEADER, REPORTTRAILER, GROUP, REPORTGRID DATASTORE, GROUPREPORT Ничего Ничего Ничего ITEM, MENU Ничего RADIOBUTTON REPORTHEADER, REPORTTRAILER, GROUP, REPORTGRID, COLONTITUL, DATASTORE, GROUPREPORT COLUMN FIELD, LABEL FIELD, LABEL SCROLLPANEL, SPLITPANEL,FORM,GRID,TABSET,TREEVIEW SCROLLPANEL, SPLITPANEL,FORM,GRID,TABSET,TREEVIEW SCROLLPANEL, SPLITPANEL,FORM,GRID,TABSET,TREEVIEW BUTTON GROUPREPORT кодировка документа зарезервированное слово document_title=название документа style = файл стиля, применяемый к данному документу buttons = "d_ok,cancel,save,new,hand_ok" Название, отображаемое в окне заголовка список типов кнопок, который будет иметь документ d_ok кнопка закрыть - закрывает документ с сохранением cancel кнопка отказ - закрывает документ без сохранения save кнопка сохранить сохраняет документ new кнопка новый - создает новый документ hand_ok кнопка применить передает выделенные в справочнике строки в документ BUTTON LABEL ACTION AACTION BACKGROUND FONT FOREGROUND Надпись на кнопке Action, Выражение калькулятора, выполняемое при нажатии кнопки Цвет фона Шрифт Цвет текста Методы - нет CHART ALIAS STYLE LEFT TOP WIDTH FREE_SPACE LEFT_OFFSET BOTTOM_OFFSET XCOLUMN LEGENDA_X_OFFSET LEGENDA_X_ASCEND LEGENDA_Y_ASCEND DATACOLUMNS LEGENDA LEGENDA_Y_OFFSET HEIGHT Имя объекта Стиль графика (график – 0, гистограмма – 1, …) Координата х левого верхнего угла Координата у левого верхнего угла ширина Пространство между столбцами гистограммы Смещение круговой диаграммы по х Смещение круговой диаграммы по у Индекс столбца выборки, размещаемы по х Смещение легенды по х Отступ значений от границы легенды по х Отступ значений от границы легенды по у Индексы столбцов выборки, которые будут использоваться при построении диаграммы {0,1} – определяет есть легенда или нет Смещение легенды по у высота Методы -нет CHECKBOX ONVALUE CHECK LABEL OFFVALUE Методы GetValue Значение, возвращаемое при положении «включен» {yes, no} начальное положение выключателя Надпись около выключателя Значение, возвращаемое при положении «выключен» Возвращает значение, ассоциированное с данным положением переключателя CHECKGROUP ALIAS LEFT TOP BG_COLOR ALIGNMENT Имя объекта Координата x левого верхнего угла Координата у левого верхнего угла Цвет фона {horizontal, vertical} расположение переключателей в группе Методы - нет COLONTITUL TYPE {TOP, BOTTON} тип колонтитула Методы – нет COLUMN font_face = <string> font_family = {0,1,2,3} font_size = <int> font_color = <color> title_font_face = <string> title_font_family = {0,1,2,3} title_font_size = <int> title_font_color = <color> bg_color = <color> visible = {YES,NO} exp = <operation> dep = <list> target = <alias> value = <string> начертание тип шрифта 0 – PLANE 1 - BOLD 2 – ITALIC 3 - BOLD&ITALIC размер шрифта цвет шрифта начертание тип шрифта размер шрифта цвет шрифта цвет фона виден ли объект вычисляемое поле список алиасов объектов зависимых от данного имя ассоциированного объекта в DATASTORE значение по умолчанию edit = <action> editexp = <operation> HALIGNMENT={LEFT,RIGHT,CENTER} VALIGNMENT={TOP,BOTTOM,CENTER} size = <int> editable = {HAND,HANDBOOK,READONLY,LIST,ALL} title = <string> действия для события редактирования выражение, вычисляемое после события редактирования выравнивание по горизонтали выравнивание по вертикали ширина столбца тип допустимого редактирования название столбца Примечания к свойству target. SQL-парсер в ядре несовершенен. Пример: select distinct bank.id_bank, bank.name_bank from settlement_account, bank ... Названием столбца становится не "BANK.ID_BANK", а "DISTINCT BANK.ID_BANK". Особенно несовершенство парсера заметно при использовании сложных названий столбцов - функции, скобки, апострофы. Если нужно взять в грид данные из столбца датастори примерно с таким именем: to_char(тырыпыры, 'dd.mm.yyyy'), то нужно использовать select from select, чтобы имя во внешнем запросе было простым. Можно использовать и те имена, которые отображаются при распознавании запроса в логе: dbi.DATASTORE.tables query= DISTINCT BANK.ID_BANK, BANK.NAME_BANK dbi.DATASTORE.tables colnam= DISTINCT BANK.ID_BANK dbi.DATASTORE.tables colnam= BANK.NAME_BANK Использование кавычек в target нужно, если решишь использовать плохо распознанное парсером название столбца. Например при названии столбца util.get(bank.name_bank) распознан он будет как dbi.DATASTORE.tables colnam= UTIL.GET(BANK И именно "UTIL.GET(BANK" надо поставить в свойство target, чтобы данные передались в грид. Методы - нет DATASTORE Alias Query Unique Default head selaction Имя объекта Запрос, выполняемый объектом Список столбцов, используемый в качестве первичных ключей таблиц Выражение калькулятора, выполняемое при создании новой строки в объекте {yes, no} определяет уровень объекта Выражение калькулятора, выполняемое SORTORDER Методы ITERATOR SETVALUE GETVALUE RETRIEVE SORT CLEARSORT FILTER SUM SIZE UPDATE NEWROW CLEAR SETSQL DELROW GETSQL GETCURROW SETCURROW FASTSETCURROW NOTIFYVIEWS ADDCOLUMN при смене текущей строки в объекте Порядок сортировки Возвращает итератор для объекта Принимает индекс столбца и новое значение, которое устанавливает в текущую строку Принимает индекс столбца, возвращает значение этого столбца из текущей строки Выполняет запрос и заполняет объект данными Устанавливает параметры сортировки и сортирует строки объекта Сбрасывает сортировку объекта Принимает выражение, возвращает объект DATASTORE, все строки которого удовлетворяют этому выражению Принимает индекс столбца, возвращает сумму элементов в этом столбце Возвращает количество строк Сбрасывает изменения, накопленные в объекте в базу данных Добавляет новую строку в DATASTORE Удаляет из объекта все строки Устанавливает запрос Принимает номер строки и удаляет эту строку Возвращает запрос Возвращает индекс текущей строки Устанавливает текущую строку (выполняя при этом скрипт selaction) Устанавливает текущую строку (не выполняя при этом скрипт selaction) Уведомляет визуальный объект, владеющий DATASTORE о том, что данные объекта изменились Принимает тип столбца и добавляет в DATASTORE новый столбец указанного типа Пример {datastore query="select clbank.name_bank, clbank.addr_bank, clbank.id_clbank, clbank.id_client, clbank.bik_bank, clbank.corr_account, clbank.ku_bank from clbank,client where clbank.id_client = client.id_client and clbank.id_client=~cl_head.client.id_client~" alias=banks editable = yes default= "clbank.id_client=~cl_head.client.id_client~" unique = "('clbank','clbank.id_clbank')" } В свойстве query определен запрос к БД, но не только. Дело в том, что к элементам DATASTORE можно обращаться - их можно считывать и в них можно записывать значения. Любое обращение к объекту в нашей системе возможно только по имени. Соответственно, если имя DATASTORE дс, то обращение к ее элементу это дс.элемент. Тут возникает два вопроса. Так как выборка, по сути, представляет собой двумерный массив, то, очевидно, в DATASTORE есть текущая строка, кроме того, именем элемента строки (поля) DATASTORE будет имя поля, указанного в запросе. Например, в приведенной выше DATASTORE есть поля clbank.name_bank, clbank.addr_bank, clbank.id_clbank, clbank.id_client, clbank.bik_bank, clbank.corr_account, clbank.ku_bank, но нет поля ku_bank или id_client. Непонимание этого факта, как показала практика, порождает много ошибок, которые трудно обнаружить. Кроме того, обратите внимание на запись запроса. Все поля в нем указаны в нотации <table_name>.<field_name>, и это не случайно. Дело в том, что когда приходит время сбрасывать данные в базу DATASTORE необходимо знать, а к какой, собственно, таблице относится данный столбец ( напомню, что в запросе могут соединяться несколько таблиц в которых есть столбцы С ОДИНАКОВЫМИ ИМЕНАМИ ) никакого удовлетворительного способа кроме синтаксического анализа запроса попросту не существует! Поэтому если вы хотите, чтобы измененный вами в DATASTORE столбец попал в нужную таблицу, настоятельно РЕКОМЕНДУЕТСЯ указывать полные имена столбцов. Итак, свойство query определяет запрос, который будет выполнен при загрузке документа. Несложно заметить, что в запросе выбираются данные из двух таблиц ( clbank,client), но при синхронизации обьекта с базой реально будет изменена только одна таблица-'clbank', поскольку только она перечислена в свойстве unique. Рассмотрим свойство unique подробнее. Это свойство служит для указания списка 'Updateable' таблиц и указания первичного ключа для каждой из таких таблиц (поскольку, не зная первичного ключа таблицы, невозможно изменять конкретные строки данной таблицы). Формат свойства в общем виде таков ('<table_name>','pk_column1',...,'pk_columnn')......('<table_name>','pk_column1',...,'pk_columnn'). Необходимо заметит, что все столбцы, перечисленные в unique, должны быть выбраны в операторе SELECT свойства query. Перейдем теперь к свойству default. Фактически, это свойство описывает, каким образом формировать вновь введенную строку DATASTORE. Нужно это вот зачем представьте себе, что у вас есть документ, в котором есть два DATASTORE ( например Шапка и Спецификация ) причем одна из DATASTORE описывает главную таблицу, а вторая - подчиненную. Очевидно, что для корректной записи описанной системы в базу, необходимо во всех вновь введенных строках второй DATASTORE сформировать правильное значение внешнего ключа, указывающее на первичный ключ строки первого DATASTORE. Как это сделать? Использовать default. Default="fk=~ds.pk~,fildn=~param~...." где fk - имя поля внешнего ключа в нашей DATASTORE, а pk- имя поля первичного ключа в DATASTORE ds. Итак, свойство default описывает, какие значения подставлять в поля вновь введенной строки. alias имя объекта, свойство очень важное, поскольку позволяет по этому имени производить операции с объектом DATASTORE без имени не собирается в коллекцию head - определяет порядок, в котором будут выполняться действия с объектом. Например, в документе несколько DATASTORE, но одно из них самое важное, тогда insert/update/delete/retrieve будут делаться сначала для него, а затем для всех остальных. Это бывает просто необходимо при работе с системами, состоящими из одной основной таблицы и нескольких подчиненных. selaction - описывает действие, которое выполняется при изменении в DATASTORE текущей строки Это нужно, если, например, нужно при хождении по одному DATASTORE, перезачитывать другое DATASTORE. DSCOLLECTION ALIAS ALIASES INITQUERY SEQQUERY SEQNAMES INITACTION Имя объекта Алиасы,, присваемые столбцам выборки INITQUERY Запрос, выполняемый при СОЗДАНИИ документа Запрос, выполняемый КАЖДЫЙ РАЗ при обращении к элементам SEQNAMES Алиасы,, присваемые столбцам выборки SEQQUERY. Примечание: после запятой не должно быть пробела, есть некий глюк в ядре. Т.е. не seqnames = "date,_user", а seqnames = "date,user" Выражение калькулятора, выполняемое при СОЗДАНИИ документа Методы DELSTORE ADDSTORE Принимает объект DATASTORE и удаляет его из коллекции, что позволяет оперировать с этим объектом в рамках особой транзакции Принимает объект DATASTORE и встраивает его в коллекцию. С этого момента все операции с этим объектом происходят в рамках общей транзакции документа. Позволяет динамически создавать объекты DATASTORE и оперировать с ними как с объектами, описанными в RML. EDITOR ALIAS TABSELEXP MULTIWINDOW Методы SETTEXT Имя объекта Выражение калькулятора, выполняемое при смене текущей закладки {yes, no} определяет возможность создания в текущем редакторе новых закладок (окон) Принимает строку и устанавливает ее в GETTEXT ADDTAB DELTAB SETCURRENTTAB GETCURRENTTAB SETTABLABEL качестве редактируемой для текущей закладки Возвращает редактируемую строку принимает номер закладки и удаляет ее Принимает номер закладки и делает ее текущей Возвращает номер текущей закладки Принимает строку, которую устанавливает в качестве названия текущей закладки FIELD {left,top} = <int> {width,height} = <int> font_face = <string> font_family = {0,1,2,3} font_size = <int> font_color = <color> bg_color = <color> visible = {YES,NO} exp = <operation> dep = <list> target = <alias> value = <string> edit = <action> editexp = <operation> верхний левый угол ширина, высота начертание тип шрифта 0 - PLANE 1 - BOLD 2 - ITALIC 3 - BOLD&ITALIC размер шрифта цвет шрифта цвет фона виден ли объект вычисляемое поле список алиасов объектов, зависимых от данного имя ассоциированного объекта в DATASTORE значение по умолчанию действия для события редактирования выражение, вычисляемое после события редактирования Методы - нет FORM ALIAS LEFT TOP WIDTH HEIGHT FONT_FACE FONT_FAMILY FONT_SIZE FONT_COLOR BG_COLOR Методы - нет Имя объекта Координата x левого верхнего угла Координата у левого верхнего угла Ширина компонента Высота компонента Имя шрифта Тип шрифта 0 - PLANE 1 - BOLD 2 - ITALIC 3 - BOLD&ITALIC Расмер шрифта Цвет текста Цвет фона GRID alias = name editable = {Yes,No} multiselect = {Yes,No} {editexp,addexp,delexp} = <operation> {edit,add,del} = <action> button_size = <int> titlebar_size = <int> buttonbar_bg_color = <color> titlebar_bg_color = <color> vscrollsize = <int> hscrollsize = <int> rowsize = <int> buttonbar_font_face = <string> buttonbar_font_family = {0,1,2,3} buttonbar_font_size = <int> buttonbar_font_color = <color> currow_color = <color> currow_bg_color = <color> Методы CURRENTVALUE GETVALUE SELECTIONVALUES RETRIEVE SETDATASTORE GETDATASTORE GETALLDATASTORE SUM имя (алиас компонента) тип редактирования Yes - редактируемый No - не редактируемый тип выделения Yes - можно выделять несколько строк No - выделяется только одна строка Действия, вызываемые соответственно при выборе, добавлении, удалении строчек объекта (если редактирование осуществляется посредством справочника) Действия, вызываемые соответственно при выборе, добавлении, удалении строчек объекта (если редактирование осуществляется вручную пользователем) Ширина панели Button_bar Ширина панели заголовков столбцов Цвет панели Button_bar Цвет панели заголовков столбцов Ширина полосы вертикальной полосы прокрутки Ширина полосы горизонтальной полосы прокрутки высота строки объекта начертание шрифта тип шрифта размер шрифта цвет шрифта Цвет текста для текущей строки Цвет текста фона для текущей строки Принимает название столбца и возвращает значение элемента данных из этого столбца текущей строки Принимает название столбца и номер строки, возвращает соответствующий элемент данных Принимает название столбца и возвращает массив значений этого столбца, соответствующий выделенным пользователям строкам Вызывает метод retrieve подчиненной DATASTORE Принимает объект DATASTORE и устанавливает ее для GRID в качестве текущей Возвращает DATASTORE GRID’а с учетом наложенных фильтров Возвращает DATASTORE GRID’а без учета наложенных фильтров Принимает имя столбца и возвращает DUMPTOFILE сумму его элементов с учетом наложенных фильтров Вызывает диалог сброса данных во внешний файл GROSSTAB ALIAS QUERY ROWCONDITION COLUMNCONDITION EVAL DATACONDITION Имя объекта Запрос, выполняемый объектом Индекс столбца выборки, из которого будут сформированы заголовки строк объекта Индекс столбца выборки, из которого будут сформированы заголовки столбцов строк объекта {max,count,sum,…} функция, применяемая к массиву, оказавшемуся на пересечении строки и столбца Индекс столбца выборки, из которого будут сформированы ряды данных объекта GROUP ALIAS Методы SUM CURRENTROW Имя объекта Принимает индекс столбца и возвращает сумму значений этого столбца в данной группе Возвращает текущую строку в группе GROUPREPORT ALIAS QUERY GROUPING SORTING TREEPARAM Имя объекта Запрос, выполняемый объектом Параметры, задающие логическую группировку (случай, когда группировка строится по ЗНАЧЕНИЯМ данных) Параметр, задающий сортировку Параметры, задающие физическую группировку (случай, когда группировка строится по связям между строками таблицы – дерево лежит в таблице) Методы - нет ITEM ALIAS LABEL ACTION EXP Имя объекта Название пункта меню Действие, выполняемое при выборе пункта меню Выражение калькулятора, выполняемое при выборе пункта меню Методы - нет LABEL ALIAS LEFT TOP WIDTH HEIGHT FONT_FACE FONT_FAMILY FONT_SIZE FONT_COLOR BG_COLOR HALIGNMENT VALIGNMENT BORDER MULTILINE WORDWRAP VALUE Имя объекта Координата хевого верхнего угла Координата у левого верхнего угла ширина высота Имя шрифта Тип шрифта 0 - PLANE 1 - BOLD 2 - ITALIC 3 - BOLD&ITALIC Расмер шрифта Цвет текста Цвет фона {left,right,center} горизонтальное выравнивание {top,right,botton} вертикальное выравнивание {none, 3dlowered, box} тип рамки {yes, no} определяет обычный текст, или многострочный {yes, no} – определяет, осуществлять или нет перенос по словам Текст Методы SETVALUE Устанавливает значение для объекта LINE LEFT TOP SIZE TYPE Координата х Координата у длина {horizontal, vertical} тип линии Методы - нет MENU ALIAS LABEL Имя объекта Текст меню (нужен при встраивании в другое меню) Методы - нет RADIOBUTTON VALUE CHECK Значение, возвращаемое компонентом, при его выборе {yes, no} начальное значение компонента LABEL Текст около компонента Методы - нет RADIOGROUP ALIAS LEFT TOP BG_COLOR ALIGNMENT Имя объекта Координата x левого верхнего угла Координата у левого верхнего угла Цвет фона {horizontal, vertical} расположение переключателей в группе Методы GETVALUE Возвращает значение, ассоциированное с выбранным переключателем REPORT BG_COLOR ORIENTATION Цвет фона для всего отчета {landscape, portrait} ориентация по умолчанию для отчета Методы – нет REPORTGRID ALIAS ROWSIZE DRAWGRID LEFT TOP Имя объекта Размер строки в отчете Параметр, определяющий способ рисования сетки в отчете Координата x левого верхнего угла Координата у левого верхнего угла Методы – нет REPORTHEADER LEFT TOP WIDTH HEIGHT BG_COLOR ALIAS Координата х левого верхнего угла Координата у левого верхнего угла ширина высота Цвет фона для компонента Имя объекта Методы – нет REPORTTRAILER LEFT TOP WIDTH HEIGHT BG_COLOR ALIAS Координата х левого верхнего угла Координата у левого верхнего угла ширина высота Цвет фона для компонента Имя объекта Методы – нет SCROLPANEL BG_COLOR Цвет фона для компонента Методы – нет SPLITPANEL ALIAS TYPE PERCENT GAPSIZE GAPCOLOR Имя объекта {horizontal,vertical} тип разбиения Процентное соотношение между размерами встроенных компонентов Величина «зазора» между компонентами Цвет «зазора» между компонентами Методы – нет TABSET ALIAS FONT_FACE FONT_FAMILY FONT_SIZE BG_COLOR TABS_ON_TOP LABELS Имя объекта Имя шрифта Тип шрифта 0 - PLANE 1 - BOLD 2 - ITALIC 3 - BOLD&ITALIC Расмер шрифта Цвет фона {yes, no} определяет положение закладок компонента – вверху или внизу Перечисленные через запятую названия закладок компонента Методы SETCUTTENTTAB Устанавливает текущую закладку TOOLBAR ALIAS ALIGN VGAP HGAP BACKGROUND Имя объекта {left, top, center} определяет выравнивание встроенных компонентов Расстояние между встраиваемыми компонентами по вертикали Расстояние между встраиваемыми компонентами по горизонтали Цвет фона FOREGROUND FONT Цвет текста Используемый шрифт Методы – нет TREEVIEW Дерево для навигации по сложным структурам данных. Источником данных является GROUPREPORT , TVNAV. Alias = name имя (алиас компонента) action=<ACTION> действие по щелчку мыши на листе дерева nodeaction=<ACTION> действие по щелчку мыши+<CTRL> на узле дерева nodefont=<FONT> фонт для узла дерева pointfont=<FONT> фонт для листа дерева background=<COLOR> цвет фона hilite=<COLOR>,<COLOR> подсветка фон/текст node=<COLOR> цвет текста для узла point=<COLOR> цвет текста для листа дерева rootname="Текст в корне дерева" Hiliting={ON,OFF} Включает/выключает подсветку Методы GETLEVEL Возвращает текущий уровень дерева TVNAV Навигатор для TREEVIEW по файлам специальной структуры. Информация о структуре находится в файле следующего вида файл node0 KOI8_R N/узел 1/node1 N/узел 2/node2 P/файл 1/file1 файл node1 KOI8_R P/файл 1/file1 P/файл 2/file2 файл node2 KOI8_R N/узел 3/node3 P/файл 1/file1 P/файл 2/file2 файл node3 KOI8_R P/файл 1/file1 Root Узел1 Узел2 Узел3 Файл1 Файл2 Файл1 Файл1 Файл2 Файл1 Где N - это узел дерева а P - его лист. KOI8_R - кодировка текста А общий формат записи для строки узла: N/название узла/имяфайла_с_описанием для листа дерева P/название листа/управляющая_информация параметры root = "path for root-file on document server" Макроязык Zeta SCRIPT 1. Введение Данный язык вырос из калькулятора и изначально служил для макроподстановок и вычисления значений в конструкциях RML. По этой причине простейшее выражение записывается как для простого калькулятора, например 10+20*1000-2 Так же можно занести результат по алиасу объекта RML STORE_ALIAS.FIELD=OTHER_STORE_ALIAS.FIELD*10 Где STORE_ALIAS и OTHER_STORE_ALIAS - алиасы некоторых объектов DATASTORE, а FIELD это столбец соответствующего DATASTORE. Но, допустим, вам надо вставить условное выражение в SQL запрос select a,b from table_c where a='~($if (FILED1=='') ('UNKNOWN') $else (FIELD1))~' Это называется макроподстановкой. Если поле редактирования с алиасом FIELD1 имеет значение, то это значение подставляется, иначе подставляется значение по умолчанию. Конечно, это можно сделать и средствами Oracle, но это более трудоемкий процесс. К тому же операции связанные с правкой серьезной базы данных могут быть неоправданным риском, в отличии от правки конкретного документа. Вообще, конструкция IF записывается как ($if (логическое выражение) (действия если выражение верно) $if (альтернативное выражение) (действия если выражение верно) ....... $else (действие если не верно ни какое из выражений) ) Например, если в обработке события вам надо в зависимости от содержимого базы открывать разные документы то можно написать следующую макро подстановку // в описании компонента GRID edit="open ~($if ( ($($(''+DS.F1)@trim)@toUpperCase) == 'LIST') ('list.rml') $if ( ($($(''+DS.F1)@trim)@toUpperCase) == 'WARE') ('ware.rml') $if ( ($($(''+DS.F1)@trim)@toUpperCase) == 'CATALOG') ('catalog.rml') $else (($alert 'Uncknown type of document '+DS.F1) ($throw 'IGNORE' '')))~ DS.CODE" Здесь можно видеть использование функций ALTER и THROW (знак '$' означает вызов функции, на самом деле IF это тоже функция), а также методов trim и toUpperCase объекта STRING. Теперь перейдем к более сложным моментам. При формировании отчетов часто приходится считать различные суммы по строкам таблицы. {label value="~($X # создаем фильтр filter = ($DS@filter 'DS.f1==ARGUMENTS.1') # создаем итератор t = ($filter@iterator) ($while ($t@next) ( # здесь могут быть и более сложные операции sum+= ($($t@value)@field 'field') ) ) ($ret sum) )~" } Здесь представлены специализированные функции для работы с объектами из DATASTORE и X-функция . X-Функция это очень важная конструкция скрипта. Она используется для создания пула локальных переменных (объект V) и все простые переменные (не содержащие точки) считаются локальными и адресуются через объект V. То есть переменная а в конструкции ($X a=10 ) реально адресуется через V.a Значение X-функции это то значение, которое указано при вызове функции RET. На вызове RET выполнение X-функции заканчивается. Соответственно X-функция используется для определения новых функций на скрипте ($defun f<a,b> ($X ($ret a+b))) определяет функцию, возвращающую сумму своих аргументов. Определение собственных функций нужно в основном при использовании рекурсивных алгоритмов. Например, для обхода дерева каталога товаров и подсчета всех значений стоимостей товаров KOI8_R DOC // universal document // секция значений по умолчанию beginexpr=" #считаем значение как сумму значений всех листьев дерева ($defun f<a> ($X ## это вообще дерево ? ($if ($a@type == 'GROUP') ( t = ($a@iterator) ($while ($t@next) (sum+= ($f ($t@value))) ) ($ret sum) ) $if ($a@type == 'DSROW') ## эта нода лист ($ret ($a@field 'SUM')) $else ($throw 'UnknownType_in_F','object '+a+' must be Group') ) ))" .............. {GroupReport Alias=GR ......... } ..... {label value="~($f(GR))~"} ....... 2. Справочник Системные объекты NUMBER STRING ARRAY HASH STACK ITERATOR *DATE DSROW GROUP DATASTORE GROUPREPORT *VIEWR *PAGE *IMAGE QEXPR Конструкции/операторы if/else for while break/continue X/Z/L/ret/goto defun try/catch/finally/throw quote alert - сообщение об ошибке trace/notrace - информация о процессе исполнения debugon/debugoff/debug - отладочная информация Функции Конструкторы системных объектов @array ($@array n) создает массив из n элементов ($@array a,b,c,d,...) создает массив [a,b,c,d,...] @hash ($@hash ) создает пустой хэш. @number ($@number ($('10.2x')@substr 0,4) ) создает число по строке @date ($@date) создает текущую дату ($@date sec) создает дату по количеству секунд прошедших с 1.1.1970 ($@date day,month,year) -/- по дню, месяцу и году. @image ($@image width,height) ($@image 'filename') Системные объекты Системные объекты обладают возможностью вызова методов применительно к объекту Пример с массивом a=($@array 10,20,30,40) ($debug ($a@size)) #printed 4 ($debug ($a@type)) #printed ARRAY ($debug ($a@ 0)) #printed 10 NUMBER Число с плавающей запятой двойной точности методы type Возвращает строку 'NUMBER' int Возвращает строку с целочисленным значением STRING Строка методы type trim indexOf lastIndexOf substr charAt toUpperCase toLowerCase size/length iterator Возвращает строку 'STRING' Удоляет лидирующие и завершающие пробелы Возвращает позицию, в которой впервые встречен символ Возвращает позицию, в которой в последний раз встречен символ Возвращает подстроку ($str@substr x) - начиная с позиции x ($str@substr x,y) - с позиции x до y Возвращает символ в указаной позиции. Переводит строку в верхний регистр. Переводит строку в нижний регистр. Возвращает количество символов. Возвращает итератор. ARRAY Массив методы type i size/length sort/backsort iterator HASH Возвращает строку 'ARRAY' Индексация по массиву Альтернативная запись ($a@ x1,x2,x3) индексов не больше, чем размерность массивa Бросает исключение IndexException Возвращает количество элементов в массиве Сортировка по возрастанию и убыванию Возвращает итератор. Хэш-таблица методы type put get iterator Возвращает строку 'HASH' Помещает в таблицу ключ и объект Возвращает по ключу объект Возвращает итератор для ключей. STACK стек методы type push pop empty Возвращает строку 'STACK' Помещает в стек Берет из стека, если стек пуст бросает исключение EmptyStackException Проверяет пуст ли стек ITERATOR Итератор методы type next prev last first value setvalue size Возвращает строку 'ITERATOR' позиционирует на следующий элемент, если только создан и еще не позиционировался то на первый элемент позиционирует на предыдущий элемент, если только создан и еще не позиционировался, то на последний элемент позиционирует на последний элемент позиционирует на первый элемент возвращает текущий элемент записывает новое значение текущего элемента, если это возможно, и возвращает старое. Если изменить значение невозможно бросает ReadOnlyException возвращает количество элементов адресуемых итератором DATE дата методы type ToNUMBER ToSTRING MM YYYY DD next iterator возвращает строку 'DATE' число секунд по Гринвичу представление в виде строки месяц год день возвращает дату со смещением на указанное число дней создает итератор с указанным шагом ( в днях) DSROW Строка объекта DATASTORE методы type field Возвращает строку 'DSROW' Возвращает значение поля по имени ($row@field 'fieldname') GROUP Группировка методы type iterator Возвращает строку 'GROUP' Создает итератор по элементам группировки DATASTORE Представление таблицы на стороне клиента методы type Возвращает строку 'DATASTORE' filter Создает фильтр для строк таблицы (полученный фильтр также является DATASTORE) ($ds@filter ($quote (логическое выражение фильтрации))) iterator Создает итератор по строкам таблицы QEXPR Вычислимое выражение методы type eval Возвращает строку 'QEXPR' Вычисляет выражение Конструкции/операторы if/else ($if (логическое выражение) (действия если выражение верно) $if (альтернативное выражение) (действия если выражение верно) ....... $else (действие если не верно ни какое из выражений) ) while ($while (логическое выражение) (действия если выражение верно) ) for ($for ((инициализация);(логическое выражение);(индексация)) (действия) ) break/continue ($break) - выход из цикла ($continue) - переход на конец цикла X/Z/L/ret/goto ($X (действие) ....... ($if ...... ($goto label2) ) ...... label1: ...... ($ret anything) ...... label2: ...... ($goto label1) ) Z-функция отличается от X-функции только тем что не создает новой таблицы локальных переменных А отличие L-функции заключается в том, что она, во-первых, не создает свою таблицу локальных переменных как и Z-функция ,а во-вторых, на ее работу влияют вызовы функций CONTINUE и BREAK . Первая повторно выполняет L-функцию, а вторая завершает выполнение со значением 0. defun ($defun FunctionName ($X ...... ($ret ....) ) ) try/catch/finally/trow ($try ( ..... ) $catch ('ExceptionName') (действие) $catch ('ExceptionName') (действие) ..... $finally (действие) ) Системные Исключения: NullException CastException IndexException FunctionNotFound HasNotMethod ReadOnlyException Syntax Any quote ($quote (выражение)) возвращает объект QEXPR для выражения 3. Построение новых конструкций (Java) Рассмотрим процесс разбора RML-документа. В процессе парсинга документ рассматривается как вложенные друг в друга контейнеры. В начале сам документ рассматривается как контейнер и его свойствами являются свойства в секции по умолчанию. Далее в нем последовательно находятся компоненты следующего уровня и т.д. В результате получается дерево из свойств компонентов, маркированных именами этих компонентов. Далее, для класса реализующего компонент вершины дерева, вызывается функция doParsing(), которая должна построить этот компонент, проинициализировать его параметрами компонента и вызвать функцию парсера getContents(), если компонент может содержать другие компоненты. Функция getContetnts создаст соответствующие объекты и вызовет для них doParsing() и т.д. В результате будет построено представление документа, которое может быть отображено на экране. public interface ParsedObject{ public Object doParsing(Proper prop,Hashtable aliases); } Пример реализации контейнерного компонента package rml; import views.*; import java.util.*; /** * компонент, реализующий форму, наполняется другими компонентами , * например, полями ввода */ public class FORM implements ParsedObject{ public Object doParsing(Proper prop,Hashtable aliases){ // создадим визуальное представление формы views.FORM frm = new views.FORM(); // поместить алиас обьекта в таблицу алиасов String alias = (String)prop.get("ALIAS"); if (alias!=null){ aliases.put(alias.toUpperCase(),(Object)frm); } // проинициализировать обьект параметрами frm.init(prop); // получить компоненты, содержащиеся в форме Object[] objs = Parser.getContent(prop,aliases); // добавить их в форму frm.addChildren(objs); // вернуть построеную форму return (Object)frm; } } Основная прелесть SCRIPT'а в том что набор его языковых конструкций и/или функций жестко не задан и поэтому может быть произвольно изменен и расширен. Для этого достаточно построить класс, реализующий вашу конструкцию, и положить его в пакет calc.functions для функций и calc.objects - для объектов. Все функции скрипта создаются как классы пакета calc.functions реализующие следующий интерфейс Напишем простую функцию для определения максимума из двух чисел package calc.functions; import calc.*; public class MAX implements ExternFunction{ // дерево для вычисления аргументов функции OP args = null; public Object eval() throws Exception{ // вычислим аргументы Object o = OP.doHardOP(args); // вычисляем пока не получим константы // должно быть два числовых аргумента Object a1,a2; if ( ( o instanceof Vector ) && ( ((Vector)o).size()==2 ) && ( (a1=((Vector)o).elementAt(0)) instanceof Double ) && ( (a2=((Vector)o).elementAt(1)) instanceof Double ) ) { // сравним арументы и вернем наибольший return ( ((Double)a1).doubleValue() > ((Double)a2).doubleValue())? a1 : a2 ; }else // иначе бросим исключение системы throw new RTException("CastException", "Function MAX must have two number arguments"); } public void init(String arg) throws Exception{ // построим дерево для вычисления аргументов args = Parser.parse1(arg.toCharArray()); } } Здесь следует обратить внимание на то, что в функции init(String) происходит только разбор выражения для аргументов , но не вычисление. Наоборот, в функции eval() происходит только вычисление уже разобранного выражения. Разбор происходит только один раз для каждого вызова функции (в каждом случае выражения для аргументов функции разные), однако, вычисление может происходить много раз, например, в цикле. В приведенном выше примере используются следующие классы и интерфейсы из пакета calc. interface ExternFunction - Этот интерфейс обязаны реализовать все конструкции-функции скрипта методы: Object eval() throws Exception - вычисление аргументов и функции void init(String arg) throws Exception - разбор строки аргументов class OP extends Tree - представление выражения в виде дерева методы: Object eval() throws Exception - вычисляет выражение static Object doHardOP(OP) throws Exception - вычисляет выражение и пока результат есть выражение вычисляет результат как новое выражение static Object doSoftOP(OP) throws Exception - вычисляет выражение class Parser - синтаксический анализатор методы: OP parse1(char[]) throws Exception - построение дерева для выражения class RTException - RunTime Exception конструктор: RTException(String exception,String messag) В сложных конструкциях, например IF, используется лексический анализатор class Lexemator - лексический анализатор конструктор: Lexemator(char[] expression) методы: int next() throws Exception - прочитать следующую лексему int type() throws Exception - тип лексемы int args() throws Exception - аргументы для тега int as_string() throws Exception - дать лексему как строку int as_double() throws Exception - дать лексему как число int as_op() throws Exception - дать лексему как операцию константы: int LDEF - идентификатор - алиас, тег, поле int LSTR - строка int LNUM - деествительное число int LEND - конец потока лексем int LOP - опкрация int LEXPR - выражение int LTAG - тег Естественно можно писать функции с неизвестным количеством аргументов. К примеру, перепишем нашу функцию так, чтобы она работала с количеством аргументов не меньше двух. package calc.functions; import calc.*; public class MAX implements ExternFunction{ // дерево для вычисления аргументов функции OP args = null; static final String except = "Function MAX must have minimum two number arguments"; public Object eval() throws Exception{ // вычислим аргументы Object o = OP.doHardOP(args); // вычисляем пока не получим константы // должно быть не мение чем два аргумента int size; if ( ( o instanceof Vector ) && ( (size=((Vector)o).size())>=2 ) && // сравним арументы и вернем наибольший int i=0; double x = Double.; double y; Vector v = (Vector)o; try { for (;i<size;++i){ y = ((Double)v.elementAt(i)).doubleValue(); x = (y>x)?y:x; } return new Double(x); }catch(ClassCastException e){ throw new RTException("CastException",except+ ",\n\tbut argument"+(i+1)+"is not NUMBER"); } }else // иначе бросим исключение системы throw new RTException("CastException",except); } public void init(String arg) throws Exception{ // построим дерево для вычисления аргументов args = Parser.parse1(arg.toCharArray()); } } Рассмотренные конструкции имеют одну очень важную особенность аргументы функции рассматриваются как список обязательно вычисляемых выражений, что не верно, например, для функции IF. package calc.functions; import calc.*; public class IF implements ExternFunction { OP expr = null; OP doing = null; OP elser = null; public Object eval() throws Exception{ //вычисляем логическое выражение Object result = expr.eval(); //если выражение истина вычисляем основное выражение //лож - альтернативное выражение, если оно есть if ( result instanceof Double ){ if ( ((Double)result).doubleValue() != 0 ) return doing.eval(); else if (elser!=null){ return elser.eval(); } }else if ( result instanceof String ){ if (((String)result).trim().toUpperCase().equals("TRUE")) return doing.eval(); else if (elser!=null){ return elser.eval(); } }else throw new RTException("SYNTAX", "RESALT of expression in IF is "+result); return new Double(0); } public void init(String arg) throws Exception{ // создаем лексический анализатор для строки аргументов Lexemator lex = new Lexemator(arg.toCharArray()); // читаем лексему lex.next(); // лексема должна быть выражением // это условное выражение if (lex.type() == Lexemator.LEXPR){ expr = Parser.parse1(lex.as_string().toCharArray()); }else throw new RTException("SYNTAX", "IF must have condition expression"); // читаем следующее выражение // это основное выражение выполняемое если условное // выражение истинно lex.next(); if (lex.type() == Lexemator.LEXPR){ doing = Parser.parse1(lex.as_string().toCharArray()); }else throw new RTException("SYNTAX", "IF must have main expression"); // далее следует конструкция // например, еще один IF или ELSE или ни чего не следует. lex.next(); switch (lex.type()){ case Lexemator.LEND: break; case Lexemator.LTAG: elser = new Func(lex.as_string(),lex.args()); break; default: throw new RTException("SYNTAX", "IF can have any alternative as tag and ONLY tag"); } } } Здесь видно, что для конструкций, в которых используются выражения, вычисляемые при некоторых условиях необходимо самостоятельно производить разбор строки аргументов, хотя и используя уже готовый лексический анализатор. Новые объекты создаются как классы пакета calc.objects и могут реализовать следующие интерфейсы Реализация конструктора, позволяет создавать объект вызовом ($@имяобьекта) public interface class_constructor { // arg - результат вычисления строки аргументов public Object constructor(Object arg) throws Exception; } Реализация методов обьекта public interface class_method { // method - имя метода // arg - результат вычисления строки аргументов public Object method(String method,Object arg) throws Exception; } Реализация метода size public interface class_size { public Double size() throws Exception; } Реализация метода type public interface class_type { public String type() throws Exception; } Реализация метода iterator public interface class_iterator { public iterator iterator() throws Exception ; } Как пример создания собственного объекта рассмотрим стек. package calc.objects; import calc.*; import java.util.Vector; public class STACK implements class_constructor,class_method,class_type{ class StackElement{ StackElement next; Object value; public StackElement(Object value,StackElement next){ this.next = next; this.value = value; } } StackElement stack = null; public STACK(){} public Object constructor(Object arg) throws Exception{ return this; } public Object method(String method,Object arg) throws Exception{ if ( method.equals("PUSH") ){ if ( arg instanceof Vector ) throw new RTException("CastException", "STACK@PUSH must called with one argument"); stack = new StackElement(arg,stack); return new Double(1); }else if ( method.equals("POP") ){ if ( stack == null ) throw new RTException("EmptyStackException", "Stack is Empty"); Object o = stack.value; stack = stack.next; return o; }else if ( method.equals("EMPTY") ){ return (stack==null)?new Double(1):new Double(0); }else throw new RTException("HasMethodException", "object STACK has not method "+method); } public String type() throws Exception{ return "STACK"; } public String toString(){ StackElement s = stack; StringBuffer sb = new StringBuffer("<"); while ( s != null ){ if ( s.value instanceof Object[]) sb.append(OP.printArray((Object[])s.value)); else sb.append(s.value); sb.append(", "); s = s.next; } sb.append("@>"); return sb.toString(); } } пример использования - файл test2 ($notrace ($X s = ($@stack) ($s@push 10) ($s@push 'text') ($s@push ($@array 1,2,3,4,5,6)) ($debug s) ($while (!($s@empty)) ($debug ''+($s@pop))) )) а так выглядит процесс исполнения [chen@wks5 zeta]$ java calc.test test2 #<[1.0,2.0,3.0,4.0,5.0,6.0], text, 10.0, @> #[1.0,2.0,3.0,4.0,5.0,6.0] #text #10.0 result: 0.0 Настройка системы Все настройки системы находятся в файле zeta.propers. Основные параметры - это где база данных и где файлы системы ( *.class,*.rml,*.gif ). база данных указывается через параметры connect.type - тип базы данных с которой работает система jdbc.diver - драйвер который будет использоваться для работы с базой dbs.propto - строка подключения к базе dbs.connect - действительно ли подключаться к базе (при отладке иногда это не нужно) Для СУБД Postgres этим параметрам выставляются следующие значения connect.type=postgres jdbc.driver=postgresql.Driver dbs.proto=jdbc:postgresql:test1 dbs.connect=yes местоположение файлов системы задается через doc.somthing=body.Snake doc.server=file:///home/chen/java/zeta/rmlfiles/ class.server=file:///home/chen/java/zeta/ image.server=file:///home/chen/java/zeta/ Если вы работаете в Linux то необходимо разрешить поддержку перекодировки для компонентов AWT это пофиксит баг JDK. awt.locale=KOI8_R enc.dtitle=on enc.field=on enc.ftitle=on в других системах закомментируйте эти строчки. Системные сообщения и надписи на специальных компонентах записываются через следующие параметры msg.OkButtonLabel=ОК msg.CanscelButtonLabel=Отмена msg.InputButtonLabel=Принять msg.BadUsersCount1=В системе уже присутствует msg.BadUsersCount2=пользователей!!!\nВам придется войти позже. msg.BadLicense=Неправильный файл лицензии. msg.BadUserOrPassword=Неправильно указано имя пользователя или пароль msg.Blocked=Объект уже заблокирован другим пользователем msg.Uncloseable=Невозможно выполнить операцию, т.к. присутствуют незакрываемые окна msg.CantConnnectToDocumentServer=Нет связи с сервером документов msg.CantConnectToDataBaseServer=Нет связи с базой данных msg.CantLoadClass=Не могу загрузить класс msg.ParsingError=Ошибка обработки документа msg.UnknownFatalError=Неизвестная Ошибка msg.ErrorReadNode=Ошибка чтения ноды msg.ErrorLoadNode=Ошибка загрузки ноды msg.RUSureExit=Вы действительно хотите нас покинуть? msg.Retriving=Ждите... Идет запрос к базе данных... msg.BadEditValuePrefix=Значение должно быть msg.BadEditValuePostfix=типа msg.BadEditValue=Вы можете продолжить редактирование \nили отменить ввод, вернув предыдущее значение msg.BadEditValueHeader=Неверно введенное значение msg.BadEditButtonEdit=Редактировать msg.BadEditButtonUndo=Предыдущее значение reg.create.msg = введите секретный ключ reg.create.btn = регистрация finddialog.caption = Поиск finddialog.pattern = Образец finddialog.direction = Направление finddialog.direction_down = Вниз finddialog.direction_up = Вверх finddialog.case = С учетом регистра finddialog.button_find = Найти finddialog.button_close = Закрыть filterdialog.caption = Параметры фильтра filterdialog.button_ok = ok filterdialog.button_cancel = Отмена filterdialog.button_reset = Сброс filterdialog.button_save = Сохранить filterdialog.label_sort = Сорт. filterdialog.label_filter = Фильтр filterdialog.label_name = Наименование filterdialog.label_bvalue = Нач. знач. filterdialog.label_evalue = Кон. знач. report.label.nextpage = -> report.label.prevpage = <report.label.firstpage = <<report.label.lastpage = ->> report.label.print = Печать report.label.pages = Стр. report.label.iz = из report.label.numcopies = Копии report.label.whatprint = Печатать report.label.mashtab = Масштаб report.label.onepage = Одну страницу report.label.allpages = Все страницы Вопросы, примеры, известные баги 1. Я описал форму и поле редактирования в ней, но не вижу его. Поле редактирование ОБЯЗАТЕЛЬНО должно содержать описание положения и размера, а также атрибут TARGET или TYPE. 2. В выражение на SCRIPT указан алиас компонента, компонент существует но возникает исключительная ситуация по отсутствию компонента. Если Вы обращаетесь к компоненту документа внутри X-функции и имя по которому вы обращаетесь не содержит точку то поставьте перед именем префикс G, например так: G.ALIASX наоборот если вы обращаетесь к переменной описанной внутри X-функции но обращение содержит точку то поставьте префикс V, например так: V.HTABLE.KEY 3. Доработки Zeta 1.6 -------------------------------------------------------------24.11.2008 Uglov Nikolay пишет: -----------------------Новый релиз на SVN. Что сделано: Переработан механизм передачи фокуса между объектами. Исправлен механизм принудительной постановки фокуса. В данный момент времени можно задавать принудительно фокус для различных компонентов. осуществляется это путем вызова функции FOCUS у объекта FOCUSER. В качестве параметра передается указательна визуальный компонент (p.<alias>). Т.е. если требуется поставить фокус на Field с альясом my_field: $g.focuser@focus p.my_field Как вы уже заметили из письма, появился новый идентификатор "p" суть его - взять адрес объекта. Зачем он нужен? Затем, что бы была возможность получить адрес любого объекта, т.к. "g" в случае его применения к такому объекту как field возвращал значение филда (т.е. то значение, которое записано в филде). Так же у объекта focuser реализованы 2 метода FOCUSNEXT и FOCUSPREVIOUS соответственно передают фокус следующему или предыдущему элементам. Что еще не сделано: Не сделан механизм задания последовательности переходов фокуса. Тут я столкнулся с некоторыми техническими сложностями, и сейчас мужественно с ними борюсь. Надеюсь закончить на этой неделе. Для тех кто не в теме: механизм задания последовательности фокуса из RML нужен для того, чтобы ограничить переход фокуса между некоторым набором визуальных компонентов в документе и задать порядок перехода фокуса в этом наборе, в данный момент он реализован в ядре, но пока не работает, поэтому систаксис пока рассказывать не буду (да он еще наверное претерпит некоторые изменения :)). Серег, специально для тебя добавил метод документа loaddbf. Кстати, отдельно наверное стоит уточнить, что метода FOCUS у документа больше не существует т.е. конструкция g.self@focus вызовет ошибку. Да, еще совсем забыл. Убрана проверка лицензии. Вообще убрана. Т.е. файлик license можно удалить :) , собственно как и mydll.dll (если эта dll еще у кого-то есть :)) -------------------------------------------------------------26.11.2008 Uglov Nikolay пишет: -----------------------Новый релиз ядра на SVN. Закончена фокусировка. Систаксис объекта focuser на данным момент следующий: {focuser {focus_item target=p.component2} {focus_item target=p.component1} {focus_item target=p.component3} {focus_item target=p.component4} } Если в RML встречается такая конструкция, то фокус будет переходить только среди описанных компонентов (focus_item) в последовательность перехода - порядок объявления компонентов. т.е. в данном примере фокус будет переходитьв следующей последовательности: component2->component1->component3->component4->component2 Marina Vagapova: Новый тип сообщений. Было sure "message" 0 – выдается окно с выбором ок, отмена, анализируется введенный ответ sure "message" 1 – выдается окно с описанием ошибки Стало sure "message" 0 – выдается окно sure "message" 1 – выдается окно sure "message" 2 – выдается окно input "message" - окно для ввода input "message" "initialValue" – с выбором ок, отмена, анализируется введенный ответ с описанием ошибки с предупреждением с сообщением, возвращает введенное значение окно для ввода + задается начальное значение Combo пример {column size=60 visible=yes title="Код unit" target=spc.id_unit halignment=left alias=idunit font_size=12 editexp = "g.idunit=($g.unitDS@getValue 'id_unit')" } {column size=60 title="Ед. изм. Combo" halignment=center target=unit.symbol_rus font_size=12 alias=name_unit values = "DS:symbol_rus" dep = "idunit" {datastore alias = unitDS query = "SELECT id_unit, symbol_rus FROM unit" editable = no } // datastore }