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

Итак, вроде бы свершилось. Наконец-то закончен первый вариант модуля для работы с Google Contacts API в Delphi. Собственно, как и все исходники в этом блоге — модуль также абсолютно бесплатен и использовать его может каждый кто хочет. Но это не главное.

Введение

Сразу следует отметить следующие несколько моментов, касающихся модуля. Во-первых, при разработке модуля я старался сделать так, чтобы разработчик, использующий модуль, как можно меньше касался работы с XML- документами в плане их парсинга, анализа и т.д. (хотя никто и не препятствует такой работе, если она будет необходима) и все данные о контактах предоставлялись в готовом виде — в свойствах, списках и т.д.

Во-вторых, текущая версия модуля выставлена как 0.1. Сделано это по нескольким причинам, в том числе и потому, что вполне возможно, что после «полевых» испытаний модуля придётся переделать часть кода, отвечающую за локализацию. Признаюсь, тут я пошел тем же путем, что и некоторые разработчики компонентов Delphi, например, как разработчики Alpha Controls и «зашил» все строки, касающиеся локализации в Res-файл. Может и не самый удобный и удачный вариант, но пока в «стерильных домашних» условиях работы модуля глюков никаких не возникало — посмотрим, что будет в дальнейшем.

И в-третьих, для нормальной работы модуля Вам необходимо использовать Delphi 2010 с библиотеками Synapse и NativeXML. Ну об этом я упоминал уже несколько раз.

С формальностями закончили. Перейдем к рассмотрению возможностей модуля.

Центральным классом с которым Вам придётся иметь дело в своих приложениях является TGoogleContact. Этот класс содержит все необходимые методы и свойства для работы с API.

Работа с TGoogleContact

TGoogleContact = class(TComponent)
  private
    FAuth: string;
    FEmail: string;
    FTotalBytes: int64;
    FBytesCount: int64;
    FGroups: TList;
    FContacts: TList;
    FOnRetriveXML: TOnRetriveXML;
    FOnBeginParse: TOnBeginParse;
    FOnEndParse: TOnEndParse;
    FOnReadData: TOnReadData;
    FMaximumResults: integer;
    FStartIndex: integer;
    FUpdatesMin: TDateTime;
    FSortOrder: TSortOrder;
    FShowDeleted: boolean;
    ...
   public 
    ...
    procedure SaveContactsToFile(const FileName: string);
    procedure LoadContactsFromFile(const FileName: string);
    property Auth: string read FAuth write SetAuth;
    property Gmail: string read FEmail write SetGmail;
    property Groups: TListread FGroups write FGroups;
    property Contacts: TListread FContacts write FContacts;
    property ContactByGroupIndex[Group: string; I: integer]: TContact read GetContact;
    property ContactsByGroup[GroupName: string]: TListread GetContactsByGroup;
    property MaximumResults: integer read FMaximumResults write SetMaximumResults;
    property StartIndex: integer read FStartIndex write SetStartIndex;
    property UpdatesMin: TDateTime read FUpdatesMin write SetUpdatesMin;
    property ShowDeleted: boolean read FShowDeleted write SetShowDeleted;
    property SortOrder: TSortOrder read FSortOrder write SetSortOrder;
    property ContactsNames: TStrings read GetContactNames;
    property GroupsNames: TStrings read GetGropsNames;
    property OnRetriveXML: TOnRetriveXML read FOnRetriveXML write FOnRetriveXML;
    property OnBeginParse: TOnBeginParse read FOnBeginParse write FOnBeginParse;
    property OnEndParse: TOnEndParse read FOnEndParse write FOnEndParse;
    property OnReadData: TOnReadData read FOnReadData write FOnReadData;
  end;

Рассмотрим работы с TGoogleContact на примере небольшого приложения для работы с контактами GMail. Весь исходник приложения, я думаю, рассматривать не стоит (ссылка на скачивание находится в конце поста), а что касается работы с TGoogleContact — рассмотрим.
Итак, прежде всего для нормально работы с сервисом нам необходимо авторизоваться. Для этого можно использовать, например, компонент TClientLogin (кстати, в скором времени ожидается его обновление).
После того, как авторизация пройдена создаем экземпляр TGogleContact и передаем значения маркера Auth и адрес электронной почты (обязательно gmail):

var Contact: TGoogleContact;
     Loginer:  TGoogleLogin;//компонент для авторизации в сервисе
     GmailContact: string;//адрес email
...
  Contact:=TGoogleContact.Create(self);
  Contact.Auth:=Loginer.Auth;
  Contact.Gmail:=GmailContact;

Теперь мы можем запросить данные по контактам и группам контактов в GMail. Так как один и тот же контакт может содержаться в нескольких группах, то Google, соответственно, передает список групп и контактов раздельно в двух XML-документах.
Вначале запрашиваем список групп:

   Contact.RetriveGroups;

Одна строка кода и список групп будет получен. Что представляет из себя метод RetriveGroups и как он работает.
RetriveGroups отправляет запрос в Google на получение XML-документа, содержащего описание групп, разбирает этот документ и формирует список групп контактов пользователя:

...
FGroups: TList; //список групп контактов
...

и возвращает в качестве результата количество групп контактов.
Как видите, каждый элемент списка представляет собой класс TContactGroup свойства которого содержат всю служебную информацию по группе.
Если Вам необходимо получить список TStrings, содержащий только имена групп (например, для заполнения ComboBox’а), то после выполнения RetriveGroups можно воспользоваться свойством TGoogleContact:

  property GroupsNames: TStrings read GetGropsNames;

следующим образом:

ComboBox1.Items.Assign(Contact.GroupsNames);

Следующий шаг — получения списка всех контактов. Для этого класс содержит аналогичный метод — RetriveContacts. Принцип действия тот же — получение контактов и формирование списка:

FContacts: TList;

Но в отличие от предыдущего метода действия RetriveContacts можно заранее настроить. По умолчанию метода использует настройки получения контактов, согласно установкам Google, то есть:
1. Возвращаются все не удаленные контакты
2. В одном документе содержится по 25 контактов
3. Контакты сортируются по убыванию даты последнего редактирования сведений.
Если Вас эти установки не удовлетворяют и вы хотите получать контакты согласно своим предпочтениям, то можно это сделать настроив свойства компонента TGoogleContact:

property MaximumResults: integer read FMaximumResults write SetMaximumResults;// максимальное количество записей контактов возвращаемое в одном фиде
property StartIndex: integer read FStartIndex write SetStartIndex;// начальный номер контакта с которого начинать принятие данных 
property UpdatesMin: TDateTime read FUpdatesMin write SetUpdatesMin;// нижняя граница обновления контактов 
property ShowDeleted: boolean read FShowDeleted write SetShowDeleted;// определяет будут ли показываться в списке удаленные контакты 
property SortOrder: TSortOrder read FSortOrder write SetSortOrder;// сортировка контактов

Например, у меня в списке содержится 2000 контактов и мне надо получить последние 100, включая все удаленные не позднее, чем 30 дней назад и получать все контакты по 50 штук в одном документе. Тогда настройки компонента будут следующими:

  Contact.MaximumResults:=50;
  Contact.StartIndex:=1900;
  Contact.ShowDeleted:=true;

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

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

property ContactsByGroup[GroupName: string]: TListread GetContactsByGroup;

В следующем примере имя группы содержится в ComboBox1, а имена контактов в ListBox1:

List:=TList.Create;
List:=Contact.ContactsByGroup[ComboBox1.Items[ComboBox1.ItemIndex]];
      for i:=0 to List.Count - 1 do
        begin
          if List[i].TagTitle.Value='' then
            if List[i].PrimaryEmail<>'' then
              ListBox1.Items.Add(List[i].PrimaryEmail)
            else
              ListBox1.Items.Add('NoName Contact')
          else
            ListBox1.Items.Add(List[i].TagTitle.Value)
        end;

Здесь мы запросили все контакты, находящиеся в выбранной группе, а также сформировали список имен контактов согласно нашим предпочтениям. Имя контакта формировалось следующим образом:
1. Проверяли заголовок для контакта (см. пост про имена).
2. Если контакт не имел заголовка, то искали адрес email контакта, который определен как основной. Здесь мы также можем ничего не получить, т.к. все адреса могут быть помечены в списке как other, т.е. обычные адреса одинаковой важности.
3. Если поиск основного адреса почты закончен неудачно, что считаем, что контакт безымянный и помечаем его как «‘NoName Contact».
Если Вам нет необходимости самостоятельно анализировать и подбирать имя для каждого контакта, то нет проблем — можно воспользоваться следующим свойством контакта (TContact):

property ContactName: string Read GetContactName;

При определении имени контакта в данном случае принимается во внимание также сетевой ник контакта.
Список контактов по группе сформировали. Что ещё может пригодится в работе? Например, Вам надо получить контакт, который содержится в определенной группе и находится, скажем в списке пятым по счёту.
Делается это следующим образом:

var Selected:TContact;
begin
  Selected:=TContact.Create();
  Selected:=Contact.ContactByGroupIndex['My Group', 5];
end;

Объект Selected в итоге будет содержать пятый по счёту контакт из группы «My Group». Если группа содержит меньшее количество контактов, то ContactByGroupIndex вернет nil.
Теперь мы вплотную подходим к работе с конкретным контактом. Для работы с контактом в TGoogleContact предусмотрены следующие методы:

function UpdateContact(aContact: TContact): boolean; overload;
    {Обновление информации о контакте с индексом <strong>Index</strong> в списке <strong>Contacts</strong>
    В случае успешно выполненной операции информация о контакте обновляется как в списке <strong>Contacts</strong>
    так и на сервере}
    function UpdateContact(index: integer): boolean; overload;
    {Получение с сервера фотографии контакта <strong>aContact</strong>. В случае, если контакт не содержит фотографии
    результатом выполнения функции будет изображение, загруженное из файла <strong>DefaultImage</strong>}
    function RetriveContactPhoto(aContact: TContact; DefaultImage: TFileName)
      : TJPEGImage; overload;
    {Получение с сервера фотографии контакта с индексом <strong>Index</strong> в списке <strong>Contacts</strong>.
    В случае, если контакт не содержит фотографии результатом выполнения функции
    будет изображение, загруженное из файла <strong>DefaultImage</strong>}
    function RetriveContactPhoto(index: integer; DefaultImage: TFileName)
      : TJPEGImage; overload;
 
    {Загружает на сервер файл <strong>PhotoFile</strong> в качестве изображения контакта,
    имеющего индекс <strong>Index</strong> в списке <strong>Contacts</strong>. Функция возращает
    <strong>True</strong> в случае успешной загрузки}
    function UpdatePhoto(index: integer; const PhotoFile: TFileName): boolean;
      overload;
    {Загружает на сервер файл <strong>PhotoFile</strong> в качестве изображения контакта
    <strong>aContact</strong>. Функция возращает <strong>True</strong> в случае успешной загрузки}
    function UpdatePhoto(aContact: TContact; const PhotoFile: TFileName)
      : boolean; overload;
    {Удаление изображения контакта <strong>aContact</strong> с сервера. Функция возвращает
    <strong>true</strong> в случае, если удаление прошло успешно}
    function DeletePhoto(aContact: TContact): boolean; overload;
    {Удаление изображения контакта с индексом <strong>Index</strong> в списке <strong>Contacts</strong>
    с сервера. Функция возвращает <strong>true</strong> в случае, если удаление прошло успешно}
    function DeletePhoto(index: integer): boolean; overload;

Как видите многие методы имеют по два варианта. В первом случае в качестве входного параметра функции выступает объект TContact, в другом — индекс элемента в общем списке контактов. В зависимости от ситуации, думаю, что будет удобно пользоваться любым из предложенных вариантов.

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

Теперь стоит немного рассказать о том, что можно сделать с контактами, используя TContact — второй по значимости класс.

Работа с TContact

Используя TContact Вы можете получать и редактировать следующую информацию по контакту:

  1. Полное имя контакта (свойство TagName)
  2. Псевдоним контакта (свойство TagNickName)
  3. День рождения контакта (свойство TagBirthDay)
  4. Организацию в которой работает контакт (TagOrganization)
  5. Список E-mail адресов контакта (свойство Emails)
  6. Список телефонов (свойство Phones)
  7. Список почтовых адресов (свойство PostalAddreses)
  8. Список значимых событий для контакта, например юбилеев, знаменательных дат и т.д. (Events)
  9. Список лиц связанных с контактом (свойство Relations)
  10. Дополнительные сведения о контакте, которые задаются в виде произвольных фрагментов текста (свойство UserFields)
  11. Список ресурсов в Сети с которыми связан контакт (свойство WebSites)
  12. Список групп в которых состоит контакт (свойство GroupMemberships)
  13. Список дополнительных средств связи с контактом, например, ICQ, Google Talk и т.д. (свойство IMs)

Чтобы подробно рассмотреть каждое из представленных свойств, видимо пришлось бы написать несколько постов и плюс к тому скопировать сюда всю документацию по API. Думаю, что это будет лишним, тем более, что в модуле я постарался оставить внятные комменарии по каждому классу.  Поэтому на сегодня информация исчерпана :) Осталось только дать Вам необходимые ссылки:

  1. Скомпилированный Demo-проект, реализующий минимальные возможности модуля, такие как получение групп и списка контактов, редактирование фотографий контактов и т.д. можно скачать здесь
  2. Модуль GContacts.pas, а также все необходимые для него вспомогательные модули можно скачать из нашего репозтория на GitHub. Там же в скором времени организуем нормальную страницу загрузок. Если хотите сразу все исходники проекта «Google API в Delphi» одним архивом, то вот ссылка.
  3. Если Вы воспользуетесь модулем и обнаружите какие-либо неточности в работе, ошибки и т.д., то оставляйте все замечания здесь.  Если Вы заинтересованы в дальнейшем развитии этого модуля, то не ждите пока его протестируют другие — участвуйте в его разработке как бета-тестеры и работа будет идти гораздо быстрее.
  4. Ну и последнее. Краткие сведения о принципе работы модуля вообще можно почерпнуть вот с этой странички Wiki.

Теперь точно все. Жду Ваших комментариев и пожеланий и баг-репортов :)

Книжная полка

Описание: Рассмотрены практические вопросы по разработке клиент-серверных приложений в среде Delphi 7 и Delphi 2005 с использованием СУБД MS SQL Server 2000, InterBase и Firebird. Приведена информация о теории построения реляционных баз данных и языке SQL. Освещены вопросы эксплуатации и администрирования СУБД.
купить книгу delphi на ЛитРес
Описание: Рассмотрены малоосвещенные вопросы программирования в Delphi. Описаны методы интеграции VCL и API. Показаны внутренние механизмы VCL и приведены примеры вмешательства в эти механизмы. Рассмотрено использование сокетов в Delphi: различные режимы их работы, особенности для протоколов TCP и UDP и др.
купить книгу delphi на ЛитРес
0 0 голоса
Рейтинг статьи
уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.
Подписаться
Уведомить о
2 Комментарий
Межтекстовые Отзывы
Посмотреть все комментарии
Aleksey
Aleksey
24/09/2016 23:23

Я вам писал по поводу удаления ссылок… Я не знаю, где размещена эта ссылка, не я размещал, мне лишь поручили такие ссылки удалить. Из информации есть только домен где установлена ссылка. Можете поиском проверить по файлам своего сайта?