WPF Google Docs Application

I have been developing a WPF application which allows a user to view/export and upload documents into their Google Docs account. Using the Google Docs .NET SDK, I was able to develop a WPF application from scratch. After the jump some code snippets and screen-shots of the application.

What is the Google Documents List API?

The API allows a client to programmatically access data stored with the Google Documents account. The following functionality is provided by the API:

  • Retrieve documents
  • Export documents
  • Upload new documents
  • Create folders and move folders
  • Modify the sharing permissions of documents

How to programmatically use the Google Documents List API?

Before you do anything you need to download the Google Docs.NET SDK framework and then import the references from the install directory into your solution project. I need to stress that you do not need the SDK and could simply use the HTTPWebRequest classes provided via .NET and make the necessary HTTP Requests via that route and parse the response data manually. To make life much easier I recommend using the SDK approach and once you are familiar with the underlying protocol move to the other approach just explained.

Firstly the client needs to authenticate with the Google Data API. I was using the Google Docs.NET SDK framework and thus the following code sample will be shown in C#.

The following using statements are needed:

    using Google.GData;
    using Google.GData.Documents;

     
     private void authenticateUser(string username, string password)
     {
         try
         {
            g_doc_service.setUserCredentials(username, password);
            g_doc_query_list = new DocumentsListQuery();
         }
         catch(AuthenticationException authE)
         {
            MessageBox.Show(authE.Message, "Invalid username/password",
                  MessageBoxButton.OK, MessageBoxImage.Exclamation);
         }
         catch(Exception errE)
         {
             MessageBox.Show(errE.Message, "Error",
                   MessageBoxButton.OK, MessageBoxImage.Exclamation);
         }
     }
 

To help me in displaying the documents back to the user in the UI I created a separate helper class with multiple properties called GoogleDoc:


   
      public class GoogleDoc
       {
           public string DocumentTitle{ get; set; }
           public System.Windows.Media.ImageSource DocumentImage{ get; set; }
           public string DocumentType { get; set; }
           public string DocumentModified { get; set; }
           public string DocumentLink { get; set; }
           public System.Windows.Media.ImageSource DocumentStar { get; set; }
           public bool DocumentStarred { get; set; }
           public string DocumentFolder { get; set; }
           public string DocumentId { get; set; }
           public string DocumentEtag { get; set; }
           public string DocumentResourceId { get; set; }
       }

Code breakdown:

Property: DocumentTitle –> represents the DocumentTitle of the selected Google Document

Property: DocumentImage -> represents an Image associated with the Documents type {spreadsheet, document, presentation}

Property: DocumentType -> represents the Documents type

Property: DocumentModified -> represents the date/time when the Document was last modified

Property: DocumentLink -> represents the URL address of the Documents location

Property: DocumentStar –> represents an Image associated with Documents Star

Property: DocumentStarred –> represents if a Document is Starred

Property: DocumentFolder –> represents the Folder the Document is a child of

Property: DocumentEtag –> a HTTP entity tag used in a HTTP request to check if a particular Document/ resource has changed without downloading the entire body of the message

Property: DocumentResourceId –> represents a unique ID associated with a Document this is used to export/modify the Document

Querying the GoogleDocuments List API for a list of Documents:

    DocumentsFeed g_doc_feed;
    
    DocumentsListQuery g_doc_query_list;
    
    g_doc_feed = g_docs_service.Query(g_doc_query_list);

As can be seen from the above code, querying the Google Document’s service returns a DocumentsFeed.

This DocumentsFeed object holds all the clients Google Documents found in their Google Docs Account. As mentioned earlier since the Google Data API relies on XML formatted RSS or Atom syndicated feeds the Google Documents are described in a universal manner via Atom. Atom is similar as RSS but provides more functionality and is the default syndication format used in the .NET SDK.

The DocumentsFeed exposes the clients Google Documents in the form of a collection of AtomEntries. Thus, it was a case of iterating through this collection:

Iterating the Documents

    foreach (DocumentEntry entry in g_doc_feed.Entries)
    {
      GoogleDoc google_doc = new GoogleDoc();
      google_doc.DocumentTitle = entry.Title.Text;
      google_doc.DocumentLink = entry.FeedUri;
      google_doc.DocumentId = entry.Id.AbsoluteUri;
      google_doc.DocumentEtag = entry.Etag;
      google_doc.DocumentResourceId = entry.AlternateUri.Content;
      Image image = new Image();
      ImageSource image_source;
    
      if (entry.IsDocument)
      {
         image_source = (ImageSource)new ImageSourceConverter()
           .ConvertFrom(@"C:\home\projects\googleDocsAPI_C\
            GoogleDocswpfApp\GoogleDocswpfApp\
            assets\Document.gif");
            google_doc.DocumentImage = image_source;
            google_doc.DocumentType = "Document";
      }
      if (entry.IsSpreadsheet)
      {
         image_source = (ImageSource)new ImageSourceConverter()
          .ConvertFrom(@"C:\home\projects\googleDocsAPI_C\
           GoogleDocswpfApp\GoogleDocswpfApp\
           assets\Spreadsheet.gif");
           google_doc.DocumentImage = image_source;
           google_doc.DocumentType = "Spreadsheet";
      }
      if (entry.IsPresentation)
      {
         image_source = (ImageSource)new ImageSourceConverter()
          .ConvertFrom(@"C:\home\projects\googleDocsAPI_C\
           GoogleDocswpfApp\GoogleDocswpfApp\
           assets\Presentation.gif");
           google_doc.DocumentImage = image_source;
           google_doc.DocumentType = "Presentation";
      }
      if (entry.IsStarred)
      {
         image_source = (ImageSource)new ImageSourceConverter().
         ConvertFrom(@"C:\home\projects\googleDocsAPI_C\
         GoogleDocswpfApp\GoogleDocswpfApp\
         assets\star.png");
         google_doc.DocumentStar = image_source;
         google_doc.DocumentStarred = true;
      }
      if (entry.ParentFolders.Count > 0)
      {
         StringBuilder folders = new StringBuilder();
         foreach (AtomLink folder in entry.ParentFolders)
            folders.Append(folder.Title);
         google_doc.DocumentFolder = folders.ToString();
      }
      google_doc.DocumentModified = entry.Updated.ToShortDateString()
        + " " + entry.Updated.ToShortTimeString();
        insertGoogleDoc(google_doc);
    }

Displaying the Google Documents in the UI

On the UI side of the application I used a ListView control in the XAML Window to display the clients Google Documents. This meant that I had to bind a collection to the ListViews ItemSource property.  Please note {Binding feeds}.

XAML code for ListView:

   <listview x:name="googleDocsView" itemssource="{Binding feeds}"
             background="AliceBlue" margin="5,12,122,119"
             selectionchanged="googleDocsView_SelectionChanged"
             allowdrop="True"
             dragover="googleDocsView_DragOver"
             drop="googleDocsView_Drop">
     <listview.view>
       <gridview x:name="view">
           <gridviewcolumn width="50" header="Starred"
             celltemplate="{StaticResource StarImageTemplate}" />
           <gridviewcolumn width="200" header="Name
             displaymemberbinding="{Binding DocumentTitle}" />
           <gridviewcolumn width="60" header="Doc Type"
             celltemplate="{StaticResource DocImageTemplate}" />
           <gridviewcolumn width="140" header="Date Modified"
             displaymemberbinding="{Binding DocumentModified}" />
          <gridviewcolumn width="140" header="Folder"
             displaymemberbinding="{Binding DocumentFolder}" />
       </gridview>
     </listview.view>
   </listview>

Returning back to our code logic. I added a ObservableCollection ‘feeds’ of type GoogleDoc which held the Google Document Items, and it is this binding collection used to populate the listview shown above.


    
    public System.Collections.ObjectModel.ObservableCollection feeds
       { get { return _feeds; } }

Screen-shots of the application

Screen-shots of the login window: Stay tuned for the next post which describes how to export/upload a document using the Google Document List API.

Last updated on 8 Oct 2009
Published on 8 Oct 2009