************************* G4 reminder *************************
These new files:

        
c:\Users\noel.GOOGLE\src-gears\googleclient\gears\opensource\gears\desktop\drag_and_drop_utils_cr.cc

are missing unit tests.
***************************************************************

Hello nigeltao,

I'd like you to do a code review.  Please execute
        g4 diff -c 10892071

or point your web browser to
        http://mondrian/10892071
(this changelist has been uploaded to Mondrian)

to review the following code:

Change 10892071 by n...@noel-gears on 2009/04/22 22:12:37 *pending*

        Drag Drop V2 chrome, restore the FileAtribute class, and file meta
        data helper routines, from the V1 implementation.  Add V2 api drag
        and drop calls, but not AcceptDrag().  Rewrite the DragSession class
        with the hopefully clearer api that I'm adding to chrome.
        
        I'll send a CL for the Makefile and desktop/desktop.cc changes once
        you land CL 10876520.
        
        PRESUBMIT=passed
        R=nigeltao
        [email protected]
        DELTA=477  (477 added, 0 deleted, 0 changed)
        OCL=10892071

Affected files ...

... 
//depot/googleclient/gears/opensource/gears/desktop/drag_and_drop_utils_cr.cc#1 
add
... 
//depot/googleclient/gears/opensource/gears/desktop/drag_and_drop_utils_cr.h#1 
add

477 delta lines: 477 added, 0 deleted, 0 changed

Also consider running:
        g4 lint -c 10892071

which verifies that the changelist doesn't introduce new style violations.

If you can't do the review, please let me know as soon as possible.  During
your review, please ensure that all new code has corresponding unit tests and
that existing unit tests are updated appropriately.  Visit
http://www/eng/code_review.html for more information.

This is a semiautomated message from "g4 mail".  Complaints or suggestions?
Mail [email protected].
Change 10892071 by n...@noel-gears on 2009/04/22 22:12:37 *pending*

        Drag Drop V2 chrome, restore the FileAtribute class, and file meta
        data helper routines, from the V1 implementation.  Add V2 api drag
        and drop calls, but not AcceptDrag().  Rewrite the DragSession class
        with the hopefully clearer api that I'm adding to chrome.
        
        I'll send a CL for the Makefile and desktop/desktop.cc changes once
        you land CL 10876520.
        
        OCL=10892071

Affected files ...

... 
//depot/googleclient/gears/opensource/gears/desktop/drag_and_drop_utils_cr.cc#1 
add
... 
//depot/googleclient/gears/opensource/gears/desktop/drag_and_drop_utils_cr.h#1 
add

==== 
//depot/googleclient/gears/opensource/gears/desktop/drag_and_drop_utils_cr.cc#1 
- 
c:\Users\noel.GOOGLE\src-gears/googleclient/gears/opensource/gears/desktop/drag_and_drop_utils_cr.cc
 ====
# action=add type=text
--- /dev/null   1970-01-01 11:00:00.000000000 +1100
+++ googleclient/gears/opensource/gears/desktop/drag_and_drop_utils_cr.cc       
2009-04-22 22:06:09.000000000 +1000
@@ -0,0 +1,436 @@
+// Copyright 2009, Google Inc.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+//  1. Redistributions of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//  2. Redistributions in binary form must reproduce the above copyright 
notice,
+//     this list of conditions and the following disclaimer in the 
documentation
+//     and/or other materials provided with the distribution.
+//  3. Neither the name of Google Inc. nor the names of its contributors may be
+//     used to endorse or promote products derived from this software without
+//     specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifdef OFFICIAL_BUILD
+// The Drag-and-Drop API has not been finalized for official builds.
+#else
+
+#include <set>
+#include <windows.h>
+#include <shlobj.h>
+
+#include "gears/desktop/drag_and_drop_utils_cr.h"
+#include "gears/base/common/base_class.h"
+#include "gears/base/common/js_runner.h"
+#include "gears/base/common/mime_detect.h"
+#include "gears/base/chrome/module_cr.h"
+#include "gears/desktop/file_dialog.h"
+
+// Chrome NPAPI drag drop event ids
+
+#define ELEMENT_EVENT_DRAGENTER 1
+#define ELEMENT_EVENT_DRAGOVER  2
+#define ELEMENT_EVENT_DRAGLEAVE 3
+#define ELEMENT_EVENT_DRAGDROP  4
+
+// Global drag state
+
+static std::set<std::string16> g_mime_set;
+static std::set<std::string16> g_type_set;
+static std::vector<std::string16> g_mimes;
+static std::vector<std::string16> g_files;
+static double g_file_total_bytes = 0;
+static size_t g_drag_files = 0;
+static uint32 g_identity = 0;
+
+// DragSession
+
+class DragSession {
+ public:
+  DragSession(NPP npp, JsObject *event)
+      : identity_(0), event_id_(0), type_(NULL), data_(NULL) {
+    event_ = NPVARIANT_TO_OBJECT(event->token());
+    context_ = CP::GetBrowsingContext(npp);
+  }
+
+  bool GetDragType() {
+    assert(!type_ && !data_);
+    // TODO(noel): call the CPAPI to return the drag type once that new
+    // api call is in chrome trunk, return false for now.
+    //
+    // browser().get_drag_data(g_cpid, context_, event_, false,
+    //     /* out parameters */ &identity_, &event_id_, &type_, &data_);
+    // return identity_ && type_;
+
+    return false;
+  }
+
+  bool GetDragData() {
+    ReleaseTypeAndData();
+    // TODO(noel): call the CPAPI to return the drag data once that new
+    // api call is in chrome trunk, return false for now.
+    //
+    // browser().get_drag_data(g_cpid, context_, event_, true,
+    //    /* out parameters */ &identity_, &event_id_, &type_, &data_);
+    // return identity_ && data_;
+
+    return false;
+  }
+
+  const uint32 identity() const { return identity_; }
+  const uint32 event_id() const { return event_id_; }
+
+  const char *type() const {
+    return identity_ && type_ ? type_ : "";
+  }
+
+  const char *data() const {
+    return identity_ && data_ ? data_ : "";
+  }
+
+  bool SetDropEffect(int effect) {
+    // TODO(noel): call the capi to set the drop effect. Return false
+    // for now.
+    // browser().set_drop_effect(g_cpid, context_, event_, effect);
+    return false;
+  }
+
+  ~DragSession() {
+    ReleaseTypeAndData();
+  }
+
+ private:
+  static const CPBrowserFuncs &browser() {
+    static const CPBrowserFuncs &kBrowser(CP::browser_funcs());
+    return kBrowser;
+  }
+
+  void ReleaseTypeAndData() {
+    if (type_) browser().free(type_);
+    if (data_) browser().free(data_);
+    type_ = data_ = NULL;
+  }
+
+  CPBrowsingContext context_;
+  NPObject *event_;
+  uint32 identity_;
+  uint32 event_id_;
+  char *type_;
+  char *data_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(DragSession);
+};
+
+// FileAttributes
+
+class FileAttributes {
+ public:
+  explicit FileAttributes(const std::string16 &path) {
+    if (!::lstrcpyn(path_, path.c_str(), MAX_PATH))
+      path_[0] = static_cast<WCHAR>(0);  // assumption: path_[MAX_PATH]
+    ResolvePath(path_);
+  }
+
+  bool Found() const {
+    if (find_handle_ != INVALID_HANDLE_VALUE)
+      return attributes_ & SFGAO_CANCOPY;
+    return false;
+  }
+
+  bool IsDirectory() const {
+    return !!(file_find_data_.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
+  }
+
+  ULONGLONG GetFileSize() const {
+    const ULARGE_INTEGER size =
+      { file_find_data_.nFileSizeLow, file_find_data_.nFileSizeHigh };
+    return size.QuadPart;
+  }
+
+  const WCHAR *GetBaseName() const {
+    return file_find_data_.cFileName;
+  }
+
+  const WCHAR *GetFileExtension() const {
+    return ::PathFindExtension(GetBaseName());
+  }
+
+  const WCHAR *GetFilePath() const { return path_; }
+
+  ~FileAttributes() {
+    ::FindClose(find_handle_);
+  }
+
+ #if defined(DEBUG)
+  #define DebugAttributes(attr) this->DisplayAttributes(attr)
+ #else
+  #define DebugAttributes(attr)
+ #endif  // DEBUG
+
+ private:
+  void ResolvePath(WCHAR *path) {
+    LOG16((L"%s\n", path));
+
+    find_handle_ = ::FindFirstFile(path, &file_find_data_);
+    attributes_ = 0;
+
+    if (find_handle_ != INVALID_HANDLE_VALUE) {
+      if (ResolveAttributes(path)) {
+        DebugAttributes(attributes_);
+        ResolveLinks(path);
+      } else {
+        ::FindClose(find_handle_);
+        find_handle_ = INVALID_HANDLE_VALUE;
+        attributes_ = 0;
+      }
+    }
+  }
+
+  DWORD ResolveAttributes(const WCHAR *path) {
+    SHFILEINFO info;
+    if (::SHGetFileInfo(path, 0, &info, sizeof(info), SHGFI_ATTRIBUTES))
+      return (attributes_ = info.dwAttributes) & SFGAO_FILESYSTEM;
+    return attributes_ = 0;
+  }
+
+  void ResolveLinks(WCHAR *path) {
+    if (attributes_ & SFGAO_LINK) {
+      if (FAILED(ResolveShortcut(path, path))) {
+        LOG16((L" link resolve failed\n"));
+      } else {
+        ::FindClose(find_handle_);
+        ResolvePath(path);
+      }
+    }
+  }
+
+  static HRESULT ResolveShortcut(const WCHAR *shortcut, WCHAR *target) {
+    LOG16((L" resolving %s\n", shortcut));
+
+    static CComPtr<IShellLink> link;
+    if (!link && FAILED(link.CoCreateInstance(CLSID_ShellLink)))
+      return E_FAIL;
+
+    static CComQIPtr<IPersistFile> file(link);
+    if (!file) return E_FAIL;
+
+    // Open the shortcut file, load its content.
+    HRESULT hr = file->Load(shortcut, STGM_READ);
+    if (FAILED(hr)) return hr;
+
+    // TODO(noel): decide if we should resolve broken link errors here
+    // for parity with the gears file picker.
+
+    // Get the shortcut target path.
+    hr = link->GetPath(target, MAX_PATH, 0, SLGP_UNCPRIORITY);
+    if (FAILED(hr)) return hr;
+
+    return S_OK;
+  }
+
+  static void DisplayAttributes(DWORD attributes) {
+    LOG16((L" "));
+    if (attributes & SFGAO_CANCOPY)
+      LOG16((L"CANCOPY "));
+    if (attributes & SFGAO_FILESYSTEM)
+      LOG16((L"FILESYSTEM "));
+    if (attributes & SFGAO_FOLDER)
+      LOG16((L"FOLDER "));
+    if (attributes & SFGAO_HIDDEN)
+      LOG16((L"HIDDEN "));
+    if (attributes & SFGAO_ISSLOW)
+      LOG16((L"ISSLOW "));
+    if (attributes & SFGAO_LINK)
+      LOG16((L"LINK "));
+    if (attributes & SFGAO_STREAM)
+      LOG16((L"STREAM "));
+    LOG16((L"\n"));
+  }
+
+ private:
+  WCHAR path_[MAX_PATH];
+  WIN32_FIND_DATA file_find_data_;
+  HANDLE find_handle_;
+  DWORD attributes_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(FileAttributes);
+};
+
+static bool FindDroppedFiles(JsRunnerInterface *runner, DragSession *drag) {
+  if (std::string(drag->type()) != "Files")
+    return false;
+
+  // "Say" there's 1 drag file until we know more; extract the files.
+  g_drag_files = 1;
+  if (!drag->GetDragData())
+    return false;
+  static const std::string16 kDelimiter(STRING16(L"\b"));
+  std::vector<std::string16> files;
+  if (!Tokenize(UTF8ToString16(drag->data()), kDelimiter, &files))
+    return false;
+
+  LOG16((L"Dragging %lu files\n", files.size()));
+  g_drag_files = files.size();
+  g_file_total_bytes = 0;
+  g_type_set.clear();
+  g_mime_set.clear();
+  g_mimes.clear();
+  g_files.clear();
+
+  for (size_t i = 0; i < g_drag_files; ++i) {
+    FileAttributes file(files[i]);
+    if (!file.Found() || file.IsDirectory())
+      return false;
+
+    LOG16((L" found %s\n", file.GetBaseName()));
+    g_type_set.insert(file.GetFileExtension());
+    g_file_total_bytes += file.GetFileSize();
+    g_files.push_back(file.GetFilePath());
+
+    g_mimes.push_back(DetectMimeTypeOfFile(g_files.back()));
+    LOG16((L" mimeType %s\n", g_mimes.back().c_str()));
+    g_mime_set.insert(g_mimes.back());
+  }
+
+  assert(g_files.size() == g_mimes.size());
+  return true;
+}
+
+// AddFileMetaData() helper.
+
+static bool ToJsArray(std::set<std::string16> const &s, JsArray *array) {
+  int length = 0;
+  if (!array || !array->GetLength(&length))
+    return false;
+
+  std::set<std::string16>::const_iterator it = s.begin();
+  while (it != s.end()) {
+    if (!array->SetElementString(length++, *it++))
+      return false;
+  }
+
+  return true;
+}
+
+static bool AddFileMetaData(JsRunnerInterface *runner, JsObject *context) {
+  assert(g_drag_files);
+
+  static const std::string16 kCount(STRING16(L"count"));
+  if (!context->SetPropertyInt(kCount, static_cast<int32>(g_files.size())))
+    return false;
+
+  if (g_files.empty())  // But there are no files we can drop.
+    return true;
+
+  static const std::string16 kBytes(STRING16(L"totalBytes"));
+  if (!context->SetPropertyDouble(kBytes, g_file_total_bytes))
+    return false;
+
+  static const std::string16 kExtensions(STRING16(L"extensions"));
+  scoped_ptr<JsArray> extensions_array(runner->NewArray());
+  if (!ToJsArray(g_type_set, extensions_array.get()))
+    return false;
+  if (!context->SetPropertyArray(kExtensions, extensions_array.get()))
+    return false;
+
+  static const std::string16 kMimes(STRING16(L"mimeTypes"));
+  scoped_ptr<JsArray> mime_array(runner->NewArray());
+  if (!ToJsArray(g_mime_set, mime_array.get()))
+    return false;
+  if (!context->SetPropertyArray(kMimes, mime_array.get()))
+    return false;
+
+  return true;
+}
+
+void SetDragCursor(ModuleEnvironment *module_environment, JsObject *event,
+                   DragAndDropCursorType cursor, std::string16 *error) {
+  NPP npp = module_environment->js_context_;
+  const int effect = (cursor == DRAG_AND_DROP_CURSOR_COPY);
+
+  DragSession drag(npp, event);
+  if (!drag.GetDragType()) {
+    *error = STRING16(L"The drag-and-drop event is invalid.");
+  } else if (!drag.SetDropEffect(effect)) {
+    *error = STRING16(L"setDragCursor() failed.");
+  }
+}
+
+bool GetDragData(ModuleEnvironment *module_environment, JsObject *event,
+                 JsObject *data, std::string16 *error) {
+  JsRunnerInterface *runner = module_environment->js_runner_;
+  NPP npp = module_environment->js_context_;
+
+  DragSession drag(npp, event);
+  if (!drag.GetDragType()) {
+    *error = STRING16(L"The drag-and-drop event is invalid.");
+    return false;
+  }
+
+  if (!g_identity || g_identity < drag.identity()) {
+    g_identity = drag.identity();
+    g_drag_files = 0;
+
+    if (!g_identity || !FindDroppedFiles(runner, &drag)) {
+      g_file_total_bytes = 0;
+      g_mime_set.clear();
+      g_type_set.clear();
+      g_files.clear();
+      g_mimes.clear();
+    }
+  }
+
+  if (g_drag_files && !AddFileMetaData(runner, data))
+    *error = STRING16(L"Failed adding file meta data.");
+
+  if (drag.event_id() != ELEMENT_EVENT_DRAGDROP)
+    return g_drag_files > 0;
+  if (!error->empty())
+    return g_drag_files > 0;
+
+  assert(drag.event_id() == ELEMENT_EVENT_DRAGDROP);
+  g_identity = 0;
+  if (!g_drag_files) {  // There are no files.
+    return false;
+  }
+
+  scoped_ptr<JsArray> array(runner->NewArray());
+  if (!array.get()) {
+    *error = STRING16(L"Failed creating javascript array.");
+    return true;
+  }
+
+  assert(std::string(drag.type()) == "Files");
+
+  if (!FileDialog::FilesToJsObjectArray(
+          g_files, module_environment, array.get(), error)) {
+    assert(!error->empty());
+    return true;
+  }
+
+  scoped_ptr<JsObject> file;  // Add the per-file mimeType.
+  for (size_t i = 0; i < g_mimes.size(); ++i) {
+    array->GetElementAsObject(i, as_out_parameter(file));
+    file->SetPropertyString(STRING16(L"mimeType"), g_mimes[i]);
+    file.reset();
+  }
+
+  static const std::string16 kFiles(STRING16(L"files"));
+  bool success = data->SetPropertyArray(kFiles, array.get());
+  LOG16((L"drop %s\n", success ? L"success" : L"failed"));
+  return success;
+}
+
+#endif  // OFFICIAL_BUILD
==== 
//depot/googleclient/gears/opensource/gears/desktop/drag_and_drop_utils_cr.h#1 
- 
c:\Users\noel.GOOGLE\src-gears/googleclient/gears/opensource/gears/desktop/drag_and_drop_utils_cr.h
 ====
# action=add type=text
--- /dev/null   1970-01-01 11:00:00.000000000 +1100
+++ googleclient/gears/opensource/gears/desktop/drag_and_drop_utils_cr.h        
2009-04-22 21:56:08.000000000 +1000
@@ -0,0 +1,41 @@
+// Copyright 2008, Google Inc.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+//  1. Redistributions of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//  2. Redistributions in binary form must reproduce the above copyright 
notice,
+//     this list of conditions and the following disclaimer in the 
documentation
+//     and/or other materials provided with the distribution.
+//  3. Neither the name of Google Inc. nor the names of its contributors may be
+//     used to endorse or promote products derived from this software without
+//     specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GEARS_DESKTOP_DRAG_AND_DROP_UTILS_CR_H__
+#define GEARS_DESKTOP_DRAG_AND_DROP_UTILS_CR_H__
+
+#include "gears/desktop/drag_and_drop_utils_common.h"
+
+bool GetDragData(ModuleEnvironment *module_environment,
+                 JsObject *event,
+                 JsObject *data_out,
+                 std::string16 *error_out);
+
+void SetDragCursor(ModuleEnvironment *module_environment,
+                   JsObject *event,
+                   DragAndDropCursorType cursor_type,
+                   std::string16 *error_out);
+
+#endif  // GEARS_DESKTOP_DRAG_AND_DROP_UTILS_CR_H__

Reply via email to