Что ж, мы разобрали подробно практически все темы, касающиеся поискового "движка" от компании SoftInform. Сегодня, наконец, завершим этот длинный, но, думаю, достаточно полезный для многих наших читателей разговор. И завершится он рассмотрением той темы, которую мы подняли в предыдущем номере - то есть, завершим рассмотрение процесса создания собственных источников документов.
Напомню, в прошлый раз мы с вами успели увидеть интерфейсные части классов, реализующих интерфейсы, необходимые для создания внешнего источника данных, с которым сможет взаимодействовать SoftInform Search SDK. Но, сами понимаете, что для того, чтобы все нормально работало, одних интерфейсных частей нам явно не хватит. Так что давайте взглянем на то, что у нас в терминах Delphi имеет название Implementation. Думаю, что в разборе всех методов всех классов, которые были приведены в предыдущей части нашего разговора о SoftInform Search SDK, нет такой уж суровой необходимости, потому что в противном случае рассказ об этом программном продукте грозит затянуться ещё.
Для начала посмотрим в сторону метода Configure класса TDSSampleClass. Думаю, что количество разнообразных параметров, которые передаются данному методу при его вызове, способно смутить того, кто еще не слишком привык к работе с SoftInform Search SDK. Но, думаю, что после того, как вы взглянете на листинг 1, все встанет на свои места.
Листинг 1
function TDSSampleClass.Configure(hWnd: LongWord; var AParameters, ACaption, ADescription: WideString; const ATranslate: ISITranslate): WordBool; var AValue: string; begin Result := False; AValue := AParameters; if InputQuery('Delphi Sample DocumentSource config', 'Enter count', AValue) then begin AValue := Trim(AValue); if StrToIntDef(AValue, 0) <= 0 then Exit; Result := True; AParameters := AValue; ACaption := 'Delphi SampleDS'; ADescription := ''; end; end;
В общем-то, код приведенного листинга достаточно прост, но мы с вами все-таки разберем подробнее, что именно там написано. Для начала стоит отметить, что этот метод должен присутствовать в классе только в том случае, если он вообще в принципе конфигурируем, что задается с помощью свойства Configurable. Конечно, в реальных приложениях окно с настройками, которое будет показывать программа, будет заметно отличаться от того предельно простого диалога, который она показывает в примере, приведенном в листинге 1.
Значение, возвращаемое рассмотренной нами функцией, определяет, успешно завершился процесс конфигурации или же изменения, которые были внесены пользователем, не должны быть в конечном итоге приняты (соответственно, и возвращаемое значение равно или не равно нулю). Из параметров, передаваемых функции, наиболее интересен AParameters. Как написано в справке, это "String where document source should store all options and parameters that was configurated". То есть, проще говоря, именно этот параметр фактически и есть результат работы всей функции. Что касается параметра ATranslate, то это просто указатель на экземпляр объекта, реализующего интерфейс ISITranslate и используемого в случае необходимости перевода содержимого окна конфигурации параметров источника документов. В большинстве же случаев трогать его нет никакой необходимости.
Что ж, давайте теперь обратимся к классу TSampleDocument и рассмотрим его конструктор. Его увидеть вы можете в листинге под номером 2.
Листинг 2
constructor TSampleDocument.Create(const ADate: TDateTime; AType: Integer); var SILibTlb: ITypeLib; AYear, AMonth, ADay, AHour, AMinute, ASecond, AMilliSecond: Word; ATitle: string; begin OleCheck(LoadRegTypeLib(LIBID_SILib, SILibMajorVersion, SILibMinorVersion, 0, SILibTlb)); inherited Create(SILibTlb, ISIDocument); FDate := ADate; FType := AType; DecodeDateTime(FDate, AYear, AMonth, ADay, AHour, AMinute, ASecond, AMilliSecond); ATitle := ''; case FType of 0: ATitle := Format('%d days', [DaysBetween(FDate, 0)]); 1: ATitle := Format('%d hours', [HoursBetween(FDate, 0)]); 2: ATitle := Format('%d minutes', [MinutesBetween(FDate, 0)]); end; FHTML := '<HTML><HEAD>'#13#10 + '<TITLE>' + ATitle + '</TITLE>'#13#10 + '</HEAD><BODY><HR>'#13#10 + Format('<B>YEAR:</B> <I>%d</I><BR>'#13#10, [AYear]) + Format('<B>MONTH:</B> <I>%d</I><BR>'#13#10, [AMonth]) + Format('<B>DAY:</B> <I>%d</I><BR>'#13#10, [ADay]); if AType > 0 then FHTML := FHTML + Format('<B>HOUR:</B> <I>%d</I><BR>'#13#10, [AHour]); if AType > 1 then FHTML := FHTML + Format('<B>MINUTE:</B> <I>%d</I><BR>'#13#10, [AMinute]); FHTML := FHTML + '<HR></BODY></HTML>'#13#10; end;
Возможно, сходу листинг может показаться перегруженным малозначительными деталями, особенно "наведением красоты" с помощью HTML-тегов, но на самом деле, мне кажется, здесь этот код не столько мешает, сколько позволяет более полно представить функционал данного метода в реальных приложениях, где, тем не менее, он наверняка будет значительно отличаться от нашего, если можно так сказать, модельного случая.
Для начала мы используем функции OleCheck и LoadRegTypeLib для того, чтобы загрузить библиотеку типов, необходимую для работы с SoftInform Search SDK, и в случае возникновения каких-то непредвиденных осложнений - вывести об этом осмысленную, с точки зрения пользователя, информацию об ошибке. После того, как библиотека типов таки загружена, мы вызываем "родительский" конструктор, ну а затем уже идет как бы логика работы класса, которая и будет отличаться от приведенной в реальных приложениях.
Теперь, я так думаю, будет не лишним поговорить об итераторах, которые мы также видели в прошлый раз. Здесь, опять-таки, рассмотрим именно конструктор, как наиболее ответственную часть всего класса, реализующего итератор для SoftInform Search SDK. Его вы можете увидеть в листинге 3.
Листинг 3
constructor TSampleDocumentItterator.Create(const ANow, ASince: TDateTime; ACount, AType: Integer); var SILibTlb: ITypeLib; begin OleCheck(LoadRegTypeLib(LIBID_SILib, SILibMajorVersion, SILibMinorVersion, 0, SILibTlb)); inherited Create(SILibTlb, ISIDocumentsItterator); FItem := 0; FNow := ANow; FType := AType; FCount := 0; case FType of 0: begin if DaysBetween(ANow, 0) <> DaysBetween(ASince, 0) then FCount := ACount; end; 1: begin if HoursBetween(ANow, 0) <> HoursBetween(ASince, 0) then FCount := ACount; end; 2: begin if MinutesBetween(ANow, 0) <> MinutesBetween(ASince, 0) then FCount := ACount; end; end; end;
В самом начале этого листинга уже знакомый нам по прошлому листингу прием с загрузкой библиотеки типов и обработкой возможных ошибок, и с последующим вызовом inherited-конструктора. Затем идет инициализация всех возможных значений внутренних полей итератора (напомню, что посмотреть на список этих самых внутренних полей вы можете в предыдущей части нашего разговора о SoftInform Search SDK, где мы рассматривали интерфейс всех классов).
Напоследок просто необходимо сказать и о процедуре инициализации всего подключаемого к SoftInform Search SDK модуля. Для этого имеет смысл воспользоваться предоставляемой Delphi секцией инициализации модуля. Текст её (он, как видите, совсем небольшой - в буквальном смысле две строчки) вы можете увидеть в листинге 4.
Листинг 4
initialization TSIPluginClassFactory_Com.Create(ComServer, TDSSampleClass, Class_DSSampleClass, 'DSSampleClass', 'Class of DSSample', ciMultiInstance, tmApartment);
Этот код содержит отсылку к одному достаточно простому классу, который мы с вами не разбирали в предыдущей статье, но который очень просто найти в примерах, идущих в стандартном комплекте поставки с SoftInform Search SDK, так что, думаю, в силу его простоты можно просто сказать, что это и есть инициализация COM-объектов, необходимых для взаимодействия нового источника документов и собственно поискового "движка".
Что ж, думаю, на этом разговор о SoftInform Search SDK можно считать успешно завершенным. Если кому-то он показался излишне подробным и затянутым, приношу свои извинения. Как, впрочем, и тем, кому, наоборот, показалось, что этот программный продукт заслуживает более подробного освещения на страницах "Компьютерных вестей". Так оно, конечно, и есть, но существует масса других интересных инструментов для разработчиков.
Еще раз хочу напомнить, что продукт SoftInform Search SDK имеет российские корни, а значит, если у вас возникнут какие-то вопросы по его использованию, на которые не смогут ответить ни примеры, ни справка (а я могу с уверенностью сказать, что так оно, скорее всего, и будет), вполне можно обращаться к создателям этого программного продукта с просьбой русским языком рассказать и показать, как его использовать. И тех трудностей, которые возникают по мере освоения этого продукта, не нужно пугаться - они неизбежны в любой сфере человеческой деятельности. Все эти сложности, которые на самом деле носят чисто технический характер, с лихвой искупаются теми преимуществами SoftInform Search SDK, которые я долго и методично перечислял в первых статьях, посвященных этому программному продукту. В общем, успешного вам освоения и внедрения SoftInform Search SDK в свои программные продукты!
Вадим СТАНКЕВИЧ,
dreamdrusch@tut.by
Комментарии
1. На каком языке написаны листинги, приведенные в статье.
2. Где это может быть применено? В тексте я так этого и не увидел. Написано лишь "для полнотекстового поиска". Где? В программах, на сайте? На чем должны бить написаны эти программы?
Вообще создается впечатление, что статья написана для очень малой группы тех, кто понимает, о чём речь, или для тех, кто эту прогу (SDK, точнее) написал. И эти люди не являются читателями КВ.
2) Это нужно было читать, опять-же, с первой статьи. А это уже седьмая.
3) Мой спонсор еще и а Apache, о проектах которого я писал шесть номеров подряд, и еще куча разных контор, о чьем софте я пишу. Да, и все мне платят. Пойду прокачусь на своем порше...
поиск рулит!