<commit_before>/*
 * Copyright 2021 Google LLC
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "experimental/graphite/include/Recorder.h"

#include "experimental/graphite/include/Recording.h"
#include "experimental/graphite/src/Caps.h"
#include "experimental/graphite/src/CommandBuffer.h"
#include "experimental/graphite/src/ContextPriv.h"
#include "experimental/graphite/src/Device.h"
#include "experimental/graphite/src/DrawBufferManager.h"
#include "experimental/graphite/src/GlobalCache.h"
#include "experimental/graphite/src/Gpu.h"
#include "experimental/graphite/src/ResourceProvider.h"
#include "experimental/graphite/src/TaskGraph.h"
#include "experimental/graphite/src/UniformCache.h"
#include "src/core/SkUniformData.h"

namespace skgpu {

#define ASSERT_SINGLE_OWNER SKGPU_ASSERT_SINGLE_OWNER(this->singleOwner())

Recorder::Recorder(sk_sp<Gpu> gpu, sk_sp<GlobalCache> globalCache)
        : fGpu(std::move(gpu))
        , fGraph(new TaskGraph)
        , fUniformCache(new UniformCache)
        , fDrawBufferManager(new DrawBufferManager(
                fResourceProvider.get(),
                fGpu->caps()->requiredUniformBufferAlignment())) {

    fResourceProvider = fGpu->makeResourceProvider(std::move(globalCache), this->singleOwner());
    SkASSERT(fResourceProvider);
}

Recorder::~Recorder() {
    ASSERT_SINGLE_OWNER
    for (auto& device : fTrackedDevices) {
        device->abandonRecorder();
    }
}

std::unique_ptr<Recording> Recorder::snap() {
    ASSERT_SINGLE_OWNER
    for (auto& device : fTrackedDevices) {
        device->flushPendingWorkToRecorder();
    }

    auto commandBuffer = fResourceProvider->createCommandBuffer();

    fGraph->addCommands(fResourceProvider.get(), commandBuffer.get());
    fDrawBufferManager->transferToCommandBuffer(commandBuffer.get());

    fGraph->reset();
    return std::unique_ptr<Recording>(new Recording(std::move(commandBuffer)));
}

void Recorder::registerDevice(Device* device) {
    ASSERT_SINGLE_OWNER
    fTrackedDevices.push_back(device);
}

void Recorder::deregisterDevice(const Device* device) {
    ASSERT_SINGLE_OWNER
    for (auto it = fTrackedDevices.begin(); it != fTrackedDevices.end(); it++) {
        if (*it == device) {
            fTrackedDevices.erase(it);
            return;
        }
    }
}

#if GR_TEST_UTILS
bool Recorder::deviceIsRegistered(Device* device) {
    for (auto& currentDevice : fTrackedDevices) {
        if (device == currentDevice) {
            return true;
        }
    }
    return false;
}
#endif

} // namespace skgpu
<commit_msg>[graphite] Don't initialize Recorder BufferManager until after initializing ResourceProvider.<commit_after>/*
 * Copyright 2021 Google LLC
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "experimental/graphite/include/Recorder.h"

#include "experimental/graphite/include/Recording.h"
#include "experimental/graphite/src/Caps.h"
#include "experimental/graphite/src/CommandBuffer.h"
#include "experimental/graphite/src/ContextPriv.h"
#include "experimental/graphite/src/Device.h"
#include "experimental/graphite/src/DrawBufferManager.h"
#include "experimental/graphite/src/GlobalCache.h"
#include "experimental/graphite/src/Gpu.h"
#include "experimental/graphite/src/ResourceProvider.h"
#include "experimental/graphite/src/TaskGraph.h"
#include "experimental/graphite/src/UniformCache.h"
#include "src/core/SkUniformData.h"

namespace skgpu {

#define ASSERT_SINGLE_OWNER SKGPU_ASSERT_SINGLE_OWNER(this->singleOwner())

Recorder::Recorder(sk_sp<Gpu> gpu, sk_sp<GlobalCache> globalCache)
        : fGpu(std::move(gpu))
        , fGraph(new TaskGraph)
        , fUniformCache(new UniformCache) {

    fResourceProvider = fGpu->makeResourceProvider(std::move(globalCache), this->singleOwner());
    fDrawBufferManager.reset(new DrawBufferManager(fResourceProvider.get(),
                                                   fGpu->caps()->requiredUniformBufferAlignment()));
    SkASSERT(fResourceProvider);
}

Recorder::~Recorder() {
    ASSERT_SINGLE_OWNER
    for (auto& device : fTrackedDevices) {
        device->abandonRecorder();
    }
}

std::unique_ptr<Recording> Recorder::snap() {
    ASSERT_SINGLE_OWNER
    for (auto& device : fTrackedDevices) {
        device->flushPendingWorkToRecorder();
    }

    auto commandBuffer = fResourceProvider->createCommandBuffer();

    fGraph->addCommands(fResourceProvider.get(), commandBuffer.get());
    fDrawBufferManager->transferToCommandBuffer(commandBuffer.get());

    fGraph->reset();
    return std::unique_ptr<Recording>(new Recording(std::move(commandBuffer)));
}

void Recorder::registerDevice(Device* device) {
    ASSERT_SINGLE_OWNER
    fTrackedDevices.push_back(device);
}

void Recorder::deregisterDevice(const Device* device) {
    ASSERT_SINGLE_OWNER
    for (auto it = fTrackedDevices.begin(); it != fTrackedDevices.end(); it++) {
        if (*it == device) {
            fTrackedDevices.erase(it);
            return;
        }
    }
}

#if GR_TEST_UTILS
bool Recorder::deviceIsRegistered(Device* device) {
    for (auto& currentDevice : fTrackedDevices) {
        if (device == currentDevice) {
            return true;
        }
    }
    return false;
}
#endif

} // namespace skgpu
<|endoftext|>


<commit_before><commit_msg>Fix for spell check underlines disappearing when user clicks out of the Text Box. WebKit removes all spell check markers in Frame::respondToChangedSelection() if, for a text box, the ShouldSpellcheckByDefault() method we have defined in the glue returns false. The problem is, ShouldSpellcheckByDefault() is also called just after the user clicks outside the textbox. As a result, it either detects that the text box is not a focussed node, or determines that the editor is not editable, and returns false, which makes the Frame remove all the markers from the corresponding document object.<commit_after><|endoftext|>


<commit_before>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "config.h"

#include "webkit/glue/plugins/plugin_lib.h"

#include "base/file_util.h"
#include "base/file_version_info.h"
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/path_service.h"
#include "base/stats_counters.h"
#include "base/string_util.h"
#include "base/sys_string_conversions.h"
#include "base/task.h"
#include "webkit/activex_shim/npp_impl.h"
#include "webkit/default_plugin/plugin_main.h"
#include "webkit/glue/glue_util.h"
#include "webkit/glue/webplugin.h"
#include "webkit/glue/webkit_glue.h"
#include "webkit/glue/plugins/plugin_instance.h"
#include "webkit/glue/plugins/plugin_host.h"
#include "webkit/glue/plugins/plugin_list.h"
#include "net/base/mime_util.h"

namespace NPAPI
{

const wchar_t kPluginLibrariesLoadedCounter[] = L"PluginLibrariesLoaded";
const wchar_t kPluginInstancesActiveCounter[] = L"PluginInstancesActive";

PluginLib::PluginMap* PluginLib::loaded_libs_;

PluginLib* PluginLib::CreatePluginLib(const std::wstring& filename) {
  // We can only have one PluginLib object per plugin as it controls the per
  // instance function calls (i.e. NP_Initialize and NP_Shutdown).  So we keep
  // a (non-ref counted) map of PluginLib objects.
  if (!loaded_libs_)
    loaded_libs_ = new PluginMap();

  PluginMap::const_iterator iter = loaded_libs_->find(filename);
  if (iter != loaded_libs_->end())
    return iter->second;

  static const InternalPluginInfo activex_shim_info_generic = {
    {kActiveXShimFileName,
     L"ActiveX Plug-in",
     L"ActiveX Plug-in provides a shim to support ActiveX controls",
     L"1, 0, 0, 1",
     L"application/x-oleobject|application/oleobject",
     L"*|*",
     L""
    },
    activex_shim::ActiveX_Shim_NP_GetEntryPoints,
    activex_shim::ActiveX_Shim_NP_Initialize,
    activex_shim::ActiveX_Shim_NP_Shutdown
  };

  static const InternalPluginInfo activex_shim_windows_media_player = {
    {kActivexShimFileNameForMediaPlayer,
     kActivexShimFileNameForMediaPlayer,
     L"Windows Media Player",
     L"1, 0, 0, 1",
     L"application/x-ms-wmp|application/asx|video/x-ms-asf-plugin|"
         L"application/x-mplayer2|video/x-ms-asf|video/x-ms-wm|audio/x-ms-wma|"
         L"audio/x-ms-wax|video/x-ms-wmv|video/x-ms-wvx",
     L"*|*|*|*|*|*|asf,asx,*|wm,*|wma,*|wax,*|wmv,*|wvx,*",
     L""
    },
    activex_shim::ActiveX_Shim_NP_GetEntryPoints,
    activex_shim::ActiveX_Shim_NP_Initialize,
    activex_shim::ActiveX_Shim_NP_Shutdown
  };

  static const InternalPluginInfo default_null_plugin_info = {
    {kDefaultPluginDllName,
     L"Default Plug-in",
     L"Provides functionality for installing third-party plug-ins",
     L"1, 0, 0, 1",
     L"*",
     L"",
     L""
    },
    default_plugin::NP_GetEntryPoints,
    default_plugin::NP_Initialize,
    default_plugin::NP_Shutdown
  };

  WebPluginInfo* info = NULL;
  const InternalPluginInfo* internal_plugin_info = NULL;
  if (filename == activex_shim_info_generic.version_info.file_name) {
    info = CreateWebPluginInfo(activex_shim_info_generic.version_info);
    internal_plugin_info = &activex_shim_info_generic;
  } else if (filename ==
             activex_shim_windows_media_player.version_info.file_name) {
    info = CreateWebPluginInfo(activex_shim_windows_media_player.version_info);
    internal_plugin_info = &activex_shim_windows_media_player;
  } else if (filename == default_null_plugin_info.version_info.file_name) {
    info = CreateWebPluginInfo(default_null_plugin_info.version_info);
    internal_plugin_info = &default_null_plugin_info;
  } else {
    info = ReadWebPluginInfo(filename);
    if (!info) {
      DLOG(INFO) << "This file isn't a valid NPAPI plugin: " << filename;
      return NULL;
    }
  }

  return new PluginLib(info, internal_plugin_info);
}

void PluginLib::UnloadAllPlugins() {
  if (loaded_libs_) {
    PluginMap::iterator lib_index;
    for (lib_index = loaded_libs_->begin(); lib_index != loaded_libs_->end();
            ++lib_index) {
      lib_index->second->Unload();
    }
    delete loaded_libs_;
    loaded_libs_ = NULL;
  }
}

void PluginLib::ShutdownAllPlugins() {
  if (loaded_libs_) {
    PluginMap::iterator lib_index;
    for (lib_index = loaded_libs_->begin(); lib_index != loaded_libs_->end();
            ++lib_index) {
      lib_index->second->Shutdown();
    }
  }
}

PluginLib::PluginLib(WebPluginInfo* info,
                     const InternalPluginInfo* internal_plugin_info)
    : web_plugin_info_(info),
      module_(0),
      initialized_(false),
      saved_data_(0),
      instance_count_(0) {
  StatsCounter(kPluginLibrariesLoadedCounter).Increment();
  memset((void*)&plugin_funcs_, 0, sizeof(plugin_funcs_));

  (*loaded_libs_)[info->file] = this;
  if (internal_plugin_info) {
    internal_ = true;
    NP_Initialize_ = internal_plugin_info->np_initialize;
    NP_GetEntryPoints_ = internal_plugin_info->np_getentrypoints;
    NP_Shutdown_ = internal_plugin_info->np_shutdown;
  } else {
    internal_ = false;
  }
}

PluginLib::~PluginLib() {
  StatsCounter(kPluginLibrariesLoadedCounter).Decrement();
  if (saved_data_ != 0) {
    // TODO - delete the savedData object here
  }
}

NPPluginFuncs *PluginLib::functions() {
  return &plugin_funcs_;
}

bool PluginLib::SupportsType(const std::string &mime_type,
                             bool allow_wildcard) {
  // Webkit will ask for a plugin to handle empty mime types.
  if (mime_type.empty())
    return false;

  for (size_t i = 0; i < web_plugin_info_->mime_types.size(); ++i) {
    const WebPluginMimeType& mime_info = web_plugin_info_->mime_types[i];
    if (net::MatchesMimeType(mime_info.mime_type, mime_type)) {
      if (!allow_wildcard && (mime_info.mime_type == "*")) {
        continue;
      }
      return true;
    }
  }
  return false;
}

NPError PluginLib::NP_Initialize() {
  if (initialized_)
    return NPERR_NO_ERROR;

  if (!Load())
    return NPERR_MODULE_LOAD_FAILED_ERROR;

  PluginHost *host = PluginHost::Singleton();
  if (host == 0)
    return NPERR_GENERIC_ERROR;

  NPError rv = NP_Initialize_(host->host_functions());
  initialized_ = (rv == NPERR_NO_ERROR);
  return rv;
}

void PluginLib::NP_Shutdown(void) {
  DCHECK(initialized_);
  NP_Shutdown_();
}

PluginInstance *PluginLib::CreateInstance(const std::string &mime_type) {
  PluginInstance *new_instance = new PluginInstance(this, mime_type);
  instance_count_++;
  StatsCounter(kPluginInstancesActiveCounter).Increment();
  DCHECK(new_instance != 0);
  return new_instance;
}

void PluginLib::CloseInstance() {
  StatsCounter(kPluginInstancesActiveCounter).Decrement();
  instance_count_--;
  // If a plugin is running in its own process it will get unloaded on process
  // shutdown.
  if ((instance_count_ == 0) &&
       webkit_glue::IsPluginRunningInRendererProcess()) {
    Unload();
    loaded_libs_->erase(web_plugin_info_->file);
    if (loaded_libs_->empty()) {
      delete loaded_libs_;
      loaded_libs_ = NULL;
    }
  }
}

bool PluginLib::Load() {
  bool rv = false;
  HMODULE module = 0;

  if (!internal_) {
    if (module_ != 0)
      return rv;

    module = LoadPluginHelper(web_plugin_info_->file);
    if (module == 0)
      return rv;

    rv = true;  // assume success now

    NP_Initialize_ = (NP_InitializeFunc)GetProcAddress(
        module, "NP_Initialize");
    if (NP_Initialize_ == 0)
      rv = false;

    NP_GetEntryPoints_ = (NP_GetEntryPointsFunc)GetProcAddress(
        module, "NP_GetEntryPoints");
    if (NP_GetEntryPoints_ == 0)
      rv = false;

    NP_Shutdown_ = (NP_ShutdownFunc)GetProcAddress(
        module, "NP_Shutdown");
    if (NP_Shutdown_ == 0)
      rv = false;
  } else {
    rv = true;
  }

  if (rv) {
    plugin_funcs_.size = sizeof(plugin_funcs_);
    plugin_funcs_.version = (NP_VERSION_MAJOR << 8) | NP_VERSION_MINOR;
    if (NP_GetEntryPoints_(&plugin_funcs_) != NPERR_NO_ERROR)
      rv = false;
  }

  if (!internal_) {
    if (rv)
      module_ = module;
    else
      FreeLibrary(module);
  }

  return rv;
}

HMODULE PluginLib::LoadPluginHelper(const std::wstring plugin_file) {
  // Switch the current directory to the plugin directory as the plugin
  // may have dependencies on dlls in this directory.
  bool restore_directory = false;
  std::wstring current_directory;
  if (PathService::Get(base::DIR_CURRENT, &current_directory)) {
    std::wstring plugin_path = file_util::GetDirectoryFromPath(
        plugin_file);
    if (!plugin_path.empty()) {
      PathService::SetCurrentDirectory(plugin_path);
      restore_directory = true;
    }
  }

  HMODULE module = LoadLibrary(plugin_file.c_str());
  if (restore_directory)
    PathService::SetCurrentDirectory(current_directory);

  return module;
}

// This class implements delayed NP_Shutdown and FreeLibrary on the plugin dll.
class FreePluginLibraryTask : public Task {
 public:
  FreePluginLibraryTask(HMODULE module, NP_ShutdownFunc shutdown_func)
      : module_(module),
        NP_Shutdown_(shutdown_func) {
  }

  ~FreePluginLibraryTask() {}

  void Run() {
    if (NP_Shutdown_)
      NP_Shutdown_();

    if (module_) {
      FreeLibrary(module_);
      module_ = NULL;
    }
  }

 private:
  HMODULE module_;
  NP_ShutdownFunc NP_Shutdown_;
  DISALLOW_EVIL_CONSTRUCTORS(FreePluginLibraryTask);
};

void PluginLib::Unload() {
  if (!internal_ && module_) {
    // In case of single process mode, a plugin can delete itself
    // by executing a script. So delay the unloading of the DLL
    // so that the plugin will have a chance to unwind.
    bool defer_unload = webkit_glue::IsPluginRunningInRendererProcess();

#if USE(JSC)
    // The plugin NPAPI instances may still be around. Delay the
    // NP_Shutdown and FreeLibrary calls at least till the next
    // peek message.
    defer_unload = true;
#endif

    if (defer_unload) {
      FreePluginLibraryTask* free_library_task =
          new FreePluginLibraryTask(module_, NP_Shutdown_);
      MessageLoop::current()->PostTask(FROM_HERE, free_library_task);
    } else {
      Shutdown();
      FreeLibrary(module_);
    }

    module_ = 0;
  }
}

void PluginLib::Shutdown() {
  if (initialized_ && !internal_) {
    NP_Shutdown();
    initialized_ = false;
  }
}

WebPluginInfo* PluginLib::CreateWebPluginInfo(const PluginVersionInfo& pvi) {
  std::vector<std::string> mime_types, file_extensions;
  std::vector<std::wstring> descriptions;
  SplitString(base::SysWideToNativeMB(pvi.mime_types), '|', &mime_types);
  SplitString(base::SysWideToNativeMB(pvi.file_extents), '|', &file_extensions);
  SplitString(pvi.file_open_names, '|', &descriptions);

  if (mime_types.empty())
    return NULL;

  WebPluginInfo *info = new WebPluginInfo();
  info->name = pvi.product_name;
  info->desc = pvi.file_description;
  info->version = pvi.file_version;
  info->file = StringToLowerASCII(pvi.file_name);

  for (size_t i = 0; i < mime_types.size(); ++i) {
    WebPluginMimeType mime_type;
    mime_type.mime_type = StringToLowerASCII(mime_types[i]);
    if (file_extensions.size() > i)
      SplitString(file_extensions[i], ',', &mime_type.file_extensions);

    if (descriptions.size() > i) {
      mime_type.description = descriptions[i];

      // Remove the extension list from the description.
      size_t ext = mime_type.description.find(L"(*");
      if (ext != std::wstring::npos) {
        if (ext > 1 && mime_type.description[ext -1] == ' ')
          ext--;

        mime_type.description.erase(ext);
      }
    }

    info->mime_types.push_back(mime_type);
  }

  return info;
}

WebPluginInfo* PluginLib::ReadWebPluginInfo(const std::wstring &filename) {
  // On windows, the way we get the mime types for the library is
  // to check the version information in the DLL itself.  This
  // will be a string of the format:  <type1>|<type2>|<type3>|...
  // For example:
  //     video/quicktime|audio/aiff|image/jpeg
  scoped_ptr<FileVersionInfo> version_info(
      FileVersionInfo::CreateFileVersionInfo(filename));
  if (!version_info.get())
    return NULL;

  PluginVersionInfo pvi;
  version_info->GetValue(L"MIMEType", &pvi.mime_types);
  version_info->GetValue(L"FileExtents", &pvi.file_extents);
  version_info->GetValue(L"FileOpenName", &pvi.file_open_names);
  pvi.product_name = version_info->product_name();
  pvi.file_description = version_info->file_description();
  pvi.file_version = version_info->file_version();
  pvi.file_name = filename;

  return CreateWebPluginInfo(pvi);
}

}  // namespace NPAPI

<commit_msg>This fixes a regression introduced by my fix for http://code.google.com/p/chromium/issues/detail?id=2846 (Revision 3262).<commit_after>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "config.h"

#include "webkit/glue/plugins/plugin_lib.h"

#include "base/file_util.h"
#include "base/file_version_info.h"
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/path_service.h"
#include "base/stats_counters.h"
#include "base/string_util.h"
#include "base/sys_string_conversions.h"
#include "base/task.h"
#include "webkit/activex_shim/npp_impl.h"
#include "webkit/default_plugin/plugin_main.h"
#include "webkit/glue/glue_util.h"
#include "webkit/glue/webplugin.h"
#include "webkit/glue/webkit_glue.h"
#include "webkit/glue/plugins/plugin_instance.h"
#include "webkit/glue/plugins/plugin_host.h"
#include "webkit/glue/plugins/plugin_list.h"
#include "net/base/mime_util.h"

namespace NPAPI
{

const wchar_t kPluginLibrariesLoadedCounter[] = L"PluginLibrariesLoaded";
const wchar_t kPluginInstancesActiveCounter[] = L"PluginInstancesActive";

PluginLib::PluginMap* PluginLib::loaded_libs_;

PluginLib* PluginLib::CreatePluginLib(const std::wstring& filename) {
  // We can only have one PluginLib object per plugin as it controls the per
  // instance function calls (i.e. NP_Initialize and NP_Shutdown).  So we keep
  // a (non-ref counted) map of PluginLib objects.
  if (!loaded_libs_)
    loaded_libs_ = new PluginMap();

  PluginMap::const_iterator iter = loaded_libs_->find(filename);
  if (iter != loaded_libs_->end())
    return iter->second;

  static const InternalPluginInfo activex_shim_info_generic = {
    {kActiveXShimFileName,
     L"ActiveX Plug-in",
     L"ActiveX Plug-in provides a shim to support ActiveX controls",
     L"1, 0, 0, 1",
     L"application/x-oleobject|application/oleobject",
     L"*|*",
     L""
    },
    activex_shim::ActiveX_Shim_NP_GetEntryPoints,
    activex_shim::ActiveX_Shim_NP_Initialize,
    activex_shim::ActiveX_Shim_NP_Shutdown
  };

  static const InternalPluginInfo activex_shim_windows_media_player = {
    {kActivexShimFileNameForMediaPlayer,
     kActivexShimFileNameForMediaPlayer,
     L"Windows Media Player",
     L"1, 0, 0, 1",
     L"application/x-ms-wmp|application/asx|video/x-ms-asf-plugin|"
         L"application/x-mplayer2|video/x-ms-asf|video/x-ms-wm|audio/x-ms-wma|"
         L"audio/x-ms-wax|video/x-ms-wmv|video/x-ms-wvx",
     L"*|*|*|*|asf,asx,*|wm,*|wma,*|wax,*|wmv,*|wvx,*",
     L""
    },
    activex_shim::ActiveX_Shim_NP_GetEntryPoints,
    activex_shim::ActiveX_Shim_NP_Initialize,
    activex_shim::ActiveX_Shim_NP_Shutdown
  };

  static const InternalPluginInfo default_null_plugin_info = {
    {kDefaultPluginDllName,
     L"Default Plug-in",
     L"Provides functionality for installing third-party plug-ins",
     L"1, 0, 0, 1",
     L"*",
     L"",
     L""
    },
    default_plugin::NP_GetEntryPoints,
    default_plugin::NP_Initialize,
    default_plugin::NP_Shutdown
  };

  WebPluginInfo* info = NULL;
  const InternalPluginInfo* internal_plugin_info = NULL;
  if (filename == activex_shim_info_generic.version_info.file_name) {
    info = CreateWebPluginInfo(activex_shim_info_generic.version_info);
    internal_plugin_info = &activex_shim_info_generic;
  } else if (filename ==
             activex_shim_windows_media_player.version_info.file_name) {
    info = CreateWebPluginInfo(activex_shim_windows_media_player.version_info);
    internal_plugin_info = &activex_shim_windows_media_player;
  } else if (filename == default_null_plugin_info.version_info.file_name) {
    info = CreateWebPluginInfo(default_null_plugin_info.version_info);
    internal_plugin_info = &default_null_plugin_info;
  } else {
    info = ReadWebPluginInfo(filename);
    if (!info) {
      DLOG(INFO) << "This file isn't a valid NPAPI plugin: " << filename;
      return NULL;
    }
  }

  return new PluginLib(info, internal_plugin_info);
}

void PluginLib::UnloadAllPlugins() {
  if (loaded_libs_) {
    PluginMap::iterator lib_index;
    for (lib_index = loaded_libs_->begin(); lib_index != loaded_libs_->end();
            ++lib_index) {
      lib_index->second->Unload();
    }
    delete loaded_libs_;
    loaded_libs_ = NULL;
  }
}

void PluginLib::ShutdownAllPlugins() {
  if (loaded_libs_) {
    PluginMap::iterator lib_index;
    for (lib_index = loaded_libs_->begin(); lib_index != loaded_libs_->end();
            ++lib_index) {
      lib_index->second->Shutdown();
    }
  }
}

PluginLib::PluginLib(WebPluginInfo* info,
                     const InternalPluginInfo* internal_plugin_info)
    : web_plugin_info_(info),
      module_(0),
      initialized_(false),
      saved_data_(0),
      instance_count_(0) {
  StatsCounter(kPluginLibrariesLoadedCounter).Increment();
  memset((void*)&plugin_funcs_, 0, sizeof(plugin_funcs_));

  (*loaded_libs_)[info->file] = this;
  if (internal_plugin_info) {
    internal_ = true;
    NP_Initialize_ = internal_plugin_info->np_initialize;
    NP_GetEntryPoints_ = internal_plugin_info->np_getentrypoints;
    NP_Shutdown_ = internal_plugin_info->np_shutdown;
  } else {
    internal_ = false;
  }
}

PluginLib::~PluginLib() {
  StatsCounter(kPluginLibrariesLoadedCounter).Decrement();
  if (saved_data_ != 0) {
    // TODO - delete the savedData object here
  }
}

NPPluginFuncs *PluginLib::functions() {
  return &plugin_funcs_;
}

bool PluginLib::SupportsType(const std::string &mime_type,
                             bool allow_wildcard) {
  // Webkit will ask for a plugin to handle empty mime types.
  if (mime_type.empty())
    return false;

  for (size_t i = 0; i < web_plugin_info_->mime_types.size(); ++i) {
    const WebPluginMimeType& mime_info = web_plugin_info_->mime_types[i];
    if (net::MatchesMimeType(mime_info.mime_type, mime_type)) {
      if (!allow_wildcard && (mime_info.mime_type == "*")) {
        continue;
      }
      return true;
    }
  }
  return false;
}

NPError PluginLib::NP_Initialize() {
  if (initialized_)
    return NPERR_NO_ERROR;

  if (!Load())
    return NPERR_MODULE_LOAD_FAILED_ERROR;

  PluginHost *host = PluginHost::Singleton();
  if (host == 0)
    return NPERR_GENERIC_ERROR;

  NPError rv = NP_Initialize_(host->host_functions());
  initialized_ = (rv == NPERR_NO_ERROR);
  return rv;
}

void PluginLib::NP_Shutdown(void) {
  DCHECK(initialized_);
  NP_Shutdown_();
}

PluginInstance *PluginLib::CreateInstance(const std::string &mime_type) {
  PluginInstance *new_instance = new PluginInstance(this, mime_type);
  instance_count_++;
  StatsCounter(kPluginInstancesActiveCounter).Increment();
  DCHECK(new_instance != 0);
  return new_instance;
}

void PluginLib::CloseInstance() {
  StatsCounter(kPluginInstancesActiveCounter).Decrement();
  instance_count_--;
  // If a plugin is running in its own process it will get unloaded on process
  // shutdown.
  if ((instance_count_ == 0) &&
       webkit_glue::IsPluginRunningInRendererProcess()) {
    Unload();
    loaded_libs_->erase(web_plugin_info_->file);
    if (loaded_libs_->empty()) {
      delete loaded_libs_;
      loaded_libs_ = NULL;
    }
  }
}

bool PluginLib::Load() {
  bool rv = false;
  HMODULE module = 0;

  if (!internal_) {
    if (module_ != 0)
      return rv;

    module = LoadPluginHelper(web_plugin_info_->file);
    if (module == 0)
      return rv;

    rv = true;  // assume success now

    NP_Initialize_ = (NP_InitializeFunc)GetProcAddress(
        module, "NP_Initialize");
    if (NP_Initialize_ == 0)
      rv = false;

    NP_GetEntryPoints_ = (NP_GetEntryPointsFunc)GetProcAddress(
        module, "NP_GetEntryPoints");
    if (NP_GetEntryPoints_ == 0)
      rv = false;

    NP_Shutdown_ = (NP_ShutdownFunc)GetProcAddress(
        module, "NP_Shutdown");
    if (NP_Shutdown_ == 0)
      rv = false;
  } else {
    rv = true;
  }

  if (rv) {
    plugin_funcs_.size = sizeof(plugin_funcs_);
    plugin_funcs_.version = (NP_VERSION_MAJOR << 8) | NP_VERSION_MINOR;
    if (NP_GetEntryPoints_(&plugin_funcs_) != NPERR_NO_ERROR)
      rv = false;
  }

  if (!internal_) {
    if (rv)
      module_ = module;
    else
      FreeLibrary(module);
  }

  return rv;
}

HMODULE PluginLib::LoadPluginHelper(const std::wstring plugin_file) {
  // Switch the current directory to the plugin directory as the plugin
  // may have dependencies on dlls in this directory.
  bool restore_directory = false;
  std::wstring current_directory;
  if (PathService::Get(base::DIR_CURRENT, &current_directory)) {
    std::wstring plugin_path = file_util::GetDirectoryFromPath(
        plugin_file);
    if (!plugin_path.empty()) {
      PathService::SetCurrentDirectory(plugin_path);
      restore_directory = true;
    }
  }

  HMODULE module = LoadLibrary(plugin_file.c_str());
  if (restore_directory)
    PathService::SetCurrentDirectory(current_directory);

  return module;
}

// This class implements delayed NP_Shutdown and FreeLibrary on the plugin dll.
class FreePluginLibraryTask : public Task {
 public:
  FreePluginLibraryTask(HMODULE module, NP_ShutdownFunc shutdown_func)
      : module_(module),
        NP_Shutdown_(shutdown_func) {
  }

  ~FreePluginLibraryTask() {}

  void Run() {
    if (NP_Shutdown_)
      NP_Shutdown_();

    if (module_) {
      FreeLibrary(module_);
      module_ = NULL;
    }
  }

 private:
  HMODULE module_;
  NP_ShutdownFunc NP_Shutdown_;
  DISALLOW_EVIL_CONSTRUCTORS(FreePluginLibraryTask);
};

void PluginLib::Unload() {
  if (!internal_ && module_) {
    // In case of single process mode, a plugin can delete itself
    // by executing a script. So delay the unloading of the DLL
    // so that the plugin will have a chance to unwind.
    bool defer_unload = webkit_glue::IsPluginRunningInRendererProcess();

#if USE(JSC)
    // The plugin NPAPI instances may still be around. Delay the
    // NP_Shutdown and FreeLibrary calls at least till the next
    // peek message.
    defer_unload = true;
#endif

    if (defer_unload) {
      FreePluginLibraryTask* free_library_task =
          new FreePluginLibraryTask(module_, NP_Shutdown_);
      MessageLoop::current()->PostTask(FROM_HERE, free_library_task);
    } else {
      Shutdown();
      FreeLibrary(module_);
    }

    module_ = 0;
  }
}

void PluginLib::Shutdown() {
  if (initialized_ && !internal_) {
    NP_Shutdown();
    initialized_ = false;
  }
}

WebPluginInfo* PluginLib::CreateWebPluginInfo(const PluginVersionInfo& pvi) {
  std::vector<std::string> mime_types, file_extensions;
  std::vector<std::wstring> descriptions;
  SplitString(base::SysWideToNativeMB(pvi.mime_types), '|', &mime_types);
  SplitString(base::SysWideToNativeMB(pvi.file_extents), '|', &file_extensions);
  SplitString(pvi.file_open_names, '|', &descriptions);

  if (mime_types.empty())
    return NULL;

  WebPluginInfo *info = new WebPluginInfo();
  info->name = pvi.product_name;
  info->desc = pvi.file_description;
  info->version = pvi.file_version;
  info->file = StringToLowerASCII(pvi.file_name);

  for (size_t i = 0; i < mime_types.size(); ++i) {
    WebPluginMimeType mime_type;
    mime_type.mime_type = StringToLowerASCII(mime_types[i]);
    if (file_extensions.size() > i)
      SplitString(file_extensions[i], ',', &mime_type.file_extensions);

    if (descriptions.size() > i) {
      mime_type.description = descriptions[i];

      // Remove the extension list from the description.
      size_t ext = mime_type.description.find(L"(*");
      if (ext != std::wstring::npos) {
        if (ext > 1 && mime_type.description[ext -1] == ' ')
          ext--;

        mime_type.description.erase(ext);
      }
    }

    info->mime_types.push_back(mime_type);
  }

  return info;
}

WebPluginInfo* PluginLib::ReadWebPluginInfo(const std::wstring &filename) {
  // On windows, the way we get the mime types for the library is
  // to check the version information in the DLL itself.  This
  // will be a string of the format:  <type1>|<type2>|<type3>|...
  // For example:
  //     video/quicktime|audio/aiff|image/jpeg
  scoped_ptr<FileVersionInfo> version_info(
      FileVersionInfo::CreateFileVersionInfo(filename));
  if (!version_info.get())
    return NULL;

  PluginVersionInfo pvi;
  version_info->GetValue(L"MIMEType", &pvi.mime_types);
  version_info->GetValue(L"FileExtents", &pvi.file_extents);
  version_info->GetValue(L"FileOpenName", &pvi.file_open_names);
  pvi.product_name = version_info->product_name();
  pvi.file_description = version_info->file_description();
  pvi.file_version = version_info->file_version();
  pvi.file_name = filename;

  return CreateWebPluginInfo(pvi);
}

}  // namespace NPAPI

<|endoftext|>


<commit_before>#include "ArgHandler.h"

ArgHandler::ArgHandler() {
	// handle defaults in the parse(..) and verify(..) functions
}
void ArgHandler::parse(int argc, char** argv) {
	desc.add_options()

    /*
    --env [ on | off ]
    --bgc [ on | off ]
    --dvm [ on | off ]
    --dsl [ on | off ]
    --dsb [ on | off ]
    --friderived  [ on | off ]
    */
    // NOT IMPLEMENTED YET - need to sort out some issues
    // ("env", boost::program_options::value<string>(&env)->default_value("on"),
    //   "Turn the environmental module on or off."
    // )
    // ("bgc", boost::program_options::value<string>(&bgc)->default_value("on"),
    //   "Turn the biogeochemical module on or off."
    // )
    // ("dvm", boost::program_options::value<string>(&dvm)->default_value("on"),
    //   "Turn the dynamic vegetation module on or off."
    // )

    ("calibrationmode", boost::program_options::value<string>(&calibrationmode)->default_value("off"),
     "(NOT IMPLEMENTED) whether or not the calibration module is on...? "
     "list of strings for modules to calibrate?"
    )
    ("loglevel,l", boost::program_options::value<string>(&loglevel)->default_value("trace"),
     "the level above which all log messages will be printed. Here are the "
     "choices: trace, debug, info, warning, error, fatal."
    )
		("mode,m", boost::program_options::value<string>(&mode)->default_value("siterun"),"change mode between siterun and regnrun")
		("control-file,f", boost::program_options::value<string>(&ctrlfile)->default_value("config/controlfile_site.txt"), "choose a control file to use")
		("cohort-id,c", boost::program_options::value<string>(&chtid)->default_value("1"), "choose a specific cohort to run")
		("space-time-config,s", boost::program_options::value<string>(), "choose spatial or temporal running mode")
		("help,h", "produces helps message, then quits")
		("version,v", "(NOT IMPLEMENTED)show the version information")
		("debug,d", "(NOT IMPLEMENTED) enable debug mode")
	;

	boost::program_options::store(boost::program_options::parse_command_line(argc, argv, desc), varmap);
	boost::program_options::notify(varmap);

  if (varmap.count("env")) {
    env = varmap["env"].as<string>();
  }
  if (varmap.count("bgc")) {
    bgc = varmap["bgc"].as<string>();
  }
  if (varmap.count("dvm")) {
    dvm = varmap["dvm"].as<string>();
  }

	if (varmap.count("cohort-id")) {
		chtid = varmap["cohort-id"].as<string>();
	}

	if (varmap.count("space-time-config")) {
		regrunmode = varmap["space-time-config"].as<string>();
	}

	if (varmap.count("help")) {
		help = true;
	}

	if (varmap.count("version")) {
		version = true;
	}

	if (varmap.count("debug")) {
		debug = true;
	}
}

void ArgHandler::verify() {
  // The regional "run mode"...loop order??
  std::cout << "Verification reuimentary - needs more programming help!\n";
  if (mode.compare("regnrun") == 0) {
    if ( (regrunmode.compare("regner1") == 0) ||
        (regrunmode.compare("regner2") == 0) ) {
      // pass, all ok
    } else {
      std::cout << "Invalid option (regrunmode). Quitting.\n";
      exit(-1);
    }
  }
}

string ArgHandler::getEnv() const {
  return env;
}
string ArgHandler::getBgc() const {
  return bgc;
}
string ArgHandler::getDvm() const {
  return dvm;
}
string ArgHandler::getCalibrationMode(){
  return calibrationmode;
}
string ArgHandler::getLogLevel(){
	return loglevel;
}
string ArgHandler::getMode(){
	return mode;
}

string ArgHandler::getCtrlfile(){
	return ctrlfile;
}

string ArgHandler::getChtid(){
	return chtid;
}

string ArgHandler::getRegrunmode(){
	return regrunmode;
}

void ArgHandler::showHelp(){
/**
 * Print out command help
 */
	std::cout << desc << std::endl;
}
<commit_msg>default value for -l works now, so no longer required<commit_after>#include "ArgHandler.h"

ArgHandler::ArgHandler() {
	// handle defaults in the parse(..) and verify(..) functions
}
void ArgHandler::parse(int argc, char** argv) {
	desc.add_options()

    /*
    --env [ on | off ]
    --bgc [ on | off ]
    --dvm [ on | off ]
    --dsl [ on | off ]
    --dsb [ on | off ]
    --friderived  [ on | off ]
    */
    // NOT IMPLEMENTED YET - need to sort out some issues
    // ("env", boost::program_options::value<string>(&env)->default_value("on"),
    //   "Turn the environmental module on or off."
    // )
    // ("bgc", boost::program_options::value<string>(&bgc)->default_value("on"),
    //   "Turn the biogeochemical module on or off."
    // )
    // ("dvm", boost::program_options::value<string>(&dvm)->default_value("on"),
    //   "Turn the dynamic vegetation module on or off."
    // )

    ("calibrationmode", boost::program_options::value<string>(&calibrationmode)->default_value("off"),
     "(NOT IMPLEMENTED) whether or not the calibration module is on...? "
     "list of strings for modules to calibrate?"
    )
    ("loglevel,l", boost::program_options::value<string>(&loglevel)->default_value("fatal"),
     "the level above which all log messages will be printed. Here are the "
     "choices: trace, debug, info, warning, error, fatal."
    )
		("mode,m", boost::program_options::value<string>(&mode)->default_value("siterun"),"change mode between siterun and regnrun")
		("control-file,f", boost::program_options::value<string>(&ctrlfile)->default_value("config/controlfile_site.txt"), "choose a control file to use")
		("cohort-id,c", boost::program_options::value<string>(&chtid)->default_value("1"), "choose a specific cohort to run")
		("space-time-config,s", boost::program_options::value<string>(), "choose spatial or temporal running mode")
		("help,h", "produces helps message, then quits")
		("version,v", "(NOT IMPLEMENTED)show the version information")
		("debug,d", "(NOT IMPLEMENTED) enable debug mode")
	;

	boost::program_options::store(boost::program_options::parse_command_line(argc, argv, desc), varmap);
	boost::program_options::notify(varmap);

  if (varmap.count("env")) {
    env = varmap["env"].as<string>();
  }
  if (varmap.count("bgc")) {
    bgc = varmap["bgc"].as<string>();
  }
  if (varmap.count("dvm")) {
    dvm = varmap["dvm"].as<string>();
  }

	if (varmap.count("cohort-id")) {
		chtid = varmap["cohort-id"].as<string>();
	}

	if (varmap.count("space-time-config")) {
		regrunmode = varmap["space-time-config"].as<string>();
	}

	if (varmap.count("help")) {
		help = true;
	}

	if (varmap.count("version")) {
		version = true;
	}

	if (varmap.count("debug")) {
		debug = true;
	}
}

void ArgHandler::verify() {
  // The regional "run mode"...loop order??
  std::cout << "Verification reuimentary - needs more programming help!\n";
  if (mode.compare("regnrun") == 0) {
    if ( (regrunmode.compare("regner1") == 0) ||
        (regrunmode.compare("regner2") == 0) ) {
      // pass, all ok
    } else {
      std::cout << "Invalid option (regrunmode). Quitting.\n";
      exit(-1);
    }
  }
}

string ArgHandler::getEnv() const {
  return env;
}
string ArgHandler::getBgc() const {
  return bgc;
}
string ArgHandler::getDvm() const {
  return dvm;
}
string ArgHandler::getCalibrationMode(){
  return calibrationmode;
}
string ArgHandler::getLogLevel(){
	return loglevel;
}
string ArgHandler::getMode(){
	return mode;
}

string ArgHandler::getCtrlfile(){
	return ctrlfile;
}

string ArgHandler::getChtid(){
	return chtid;
}

string ArgHandler::getRegrunmode(){
	return regrunmode;
}

void ArgHandler::showHelp(){
/**
 * Print out command help
 */
	std::cout << desc << std::endl;
}
<|endoftext|>


<commit_before>/*
    Authors: Darya Filippova, Geet Duggal, Rob Patro
    dfilippo | geet | robp @cs.cmu.edu
*/

#include <limits>
#include <boost/heap/binomial_heap.hpp>
#include <boost/range/irange.hpp>
#include <algorithm>
#include "ArmatusDAG.hpp"

ArmatusDAG::ArmatusDAG(ArmatusParams& p) :
	subProbs(SubProbsVec(p.n)),
    edgeWeights(EdgeWeightsVec(p.n, vector<double>())) {
	params = &p;
}

void ArmatusDAG::build() {
	// Since building the DAG visits everything in the same order as computing
	// a single optimial solution, I've had this function also fill out the
	// necessary information to obtain a backtrace of the opt. sln.
	subProbs[0].topK.push_back({std::numeric_limits<size_t>::max(), 0, 0.0});
	// What's the right condition here?
	// subProbs[1].topK.push_back({0, 0, std::max(q(0,1), 0.0)});

    for (size_t l : boost::irange(size_t{1}, params->n)) {
        // was this
  	    // edgeWeights[l].resize(l-1);
        // now this
  	    edgeWeights[l].resize(l);
  	    size_t chosenEdge = 0;
  	    double bestScore = 0.0;
  	    for (size_t k : boost::irange(size_t{0}, l)) {
  	    	// The last domain is [k,l]
  	    	double edgeWeight = std::max(q(k, l), 0.0);
            edgeWeights[l][k] = edgeWeight;
            double totalScore = edgeWeight;
            bool isDomain = edgeWeight > 0.0;
            bool isPrevDomain = (k == 0) ? true : false;
            if (k > 0) {
                double prevDomainScore = subProbs[k-1].topK[0].score;
                isPrevDomain = prevDomainScore > 0.0;
                // The score of this solution is the benefit we get from traversing
                // the edge + the best score available at the child
                totalScore += prevDomainScore;
             }
             if (isDomain or isPrevDomain) {
                 if (totalScore > bestScore) {
                     bestScore = totalScore;
                     chosenEdge = k;
                 }
            }
  	    }

  	    // Put our best solution on the stack.
  	    subProbs[l].topK.push_back({chosenEdge, 0, bestScore});
    }
}

double ArmatusDAG::s(size_t k, size_t l) {
	size_t d = l-k+1;
    return params->sums(k, l)/ std::pow(static_cast<double>(d),params->gamma);
}

double ArmatusDAG::q(size_t k, size_t l) {
	size_t d = l-k+1;
	return (s(k, l) - params->mu[d]);
}

/**
*  This interface is *wrong* but I wanted to sketch the
*  basic algo.
**/
void ArmatusDAG::computeTopK(uint32_t k) {
    for (size_t l : boost::irange(size_t{1}, params->n)) {
        std::function<bool (const BackPointer&, const BackPointer&)> BackPointerComparator = [l, this] (const BackPointer& x, const BackPointer& y) -> bool {
            auto scoreX = this->edgeWeights[l][x.edge];
            if (x.edge > 0) { scoreX += this->subProbs[x.edge-1].topK[x.childSolution].score; }
            auto scoreY = this->edgeWeights[l][y.edge];
            if (y.edge > 0) { scoreY += this->subProbs[y.edge-1].topK[y.childSolution].score; }

            return scoreX < scoreY;
        };

        boost::heap::binomial_heap<BackPointer,
            boost::heap::compare<decltype(BackPointerComparator)>> pq(BackPointerComparator);
        for (size_t j : boost::irange(size_t{0}, l)) {
            if (j > 0) {
                size_t i = j - 1;
                bool isDomain = edgeWeights[l][j] > 0.0;
                bool prevIsDomain = (subProbs[i].topK.size() > 0 and edgeWeights[i].size() > 0) ? edgeWeights[i][subProbs[i].topK[0].edge] > 0 : true;
                if (j == 1) { prevIsDomain = false; }

                if (isDomain or prevIsDomain) {
                    double score = edgeWeights[l][j] + subProbs[i].topK[0].score;
                    pq.push({j, 0, score});
                }
            } else {
                double score = edgeWeights[l][0];
                pq.push({0, 0, score});
            }
        }

        while (subProbs[l].topK.size() < k and !pq.empty()) {
            auto bp = pq.top();
            pq.pop();
            size_t j = bp.edge;
            if (j > 0) {
                bool alreadyFound{false};
                if (bp != subProbs[l].topK[0] ) { subProbs[l].topK.push_back(bp); }
                size_t nextSlnIdx = bp.childSolution + 1;
                bool isDomain = edgeWeights[l][j] > 0.0;

                size_t i = j - 1;
                //std::cout << bp.edge << "\t" << subProbs.size() << endl;
                if (nextSlnIdx < subProbs[i].topK.size()) {
                    bool prevIsDomain = edgeWeights[i][subProbs[i].topK[nextSlnIdx].edge] > 0.0;
                    if (isDomain or prevIsDomain ) {
                        double score = edgeWeights[l][j] + subProbs[i].topK[nextSlnIdx].score;
                        pq.push({j, nextSlnIdx, score});
                    }
                }
            } else {
                if (bp != subProbs[l].topK[0] ) { subProbs[l].topK.push_back(bp); }
            }
        }
    }

    // size_t sln = 0;
    // while (sln < k and sln < subProbs[params->n-1].topK.size()) {
    // 	std::cerr << "solution " << sln << " has score " << subProbs[params->n-1].topK[sln].score << "\n";
    // 	++sln;
    // }
}

WeightedDomainEnsemble ArmatusDAG::extractTopK(uint32_t k) {

  const size_t INVALID = std::numeric_limits<size_t>::max();
  // We skip 0 since that was already extracted by viterbiPath
  uint32_t currSln{0};

  WeightedDomainEnsemble solutions{ DomainEnsemble(k, DomainSet()), Weights(k, 0.0) };
  auto root = params->n-1;
  auto topScore = subProbs[root].topK[0].score;
  auto scores = Weights(k, 0.0);

  while (currSln < k and currSln < subProbs[root].topK.size()) {
    auto currentScore = subProbs[root].topK[currSln].score;
    scores[currSln] = currentScore;
    auto& currentDomainSet = solutions.domainSets[currSln];
    solutions.weights[currSln] = currentScore / topScore;

    // Which solution to use at the child
    auto bp = currSln;
    int64_t end = params->n-1;
    bool prevWasDomain = true;
    bool done{false};
    Domain prevDomain(root, root);

    while (end > 0) { // and subProbs[end].topK[bp].edge != INVALID) {
      //std::cerr << "end: " << end << "\n";
      size_t begin = subProbs[end].topK[bp].edge;
      size_t start = begin;
//      if (subProbs[begin].topK[subProbs[end].topK[bp].childSolution].edge != INVALID)
//         start++;
      Domain d(start, end);
      if (d.score(*params) > 0.0){
         currentDomainSet.push_back(d);
         prevWasDomain = true;
      } else {
         //currentDomainSet.push_back(d);
        if (!prevWasDomain) {
                std::cerr << "WHAT: solution contained two adjacent non-domains; current domain is (" << start << ", " << end << ") prev domain was (" << prevDomain.start << ", " << prevDomain.end << ")\n";
        }
        prevWasDomain = false;
      }
      prevDomain = d;
      bp = subProbs[end].topK[bp].childSolution;
      end = begin-1;
   }

    ++currSln;
  }

  /**
   * consistency check all the extracted domains (for debug purposes only,
   * take this out for release / speed).
   */
  size_t c = 0;
  double eps = 1e-3;
  for (auto& ds : solutions.domainSets) {
    double score = 0.0;
    for (auto& d : ds) {
      score += d.score(*params);
    }
    if (std::abs(score - scores[c]) > eps) {
      std::cerr << "For solution [" << c << "], the recorded score was " << scores[c] << " but extracted domains sum to " << score << "\n";
    }
    ++c;
  }

  return solutions;
}

vector<Domain> ArmatusDAG::viterbiPath() {
	vector<Domain> domains;
  const size_t INVALID = std::numeric_limits<size_t>::max();
	size_t end = params->n-1;
	//std::cerr << "Best score is " << subProbs[end].topK[0].score << "\n";

	while (subProbs[end].topK[0].edge != INVALID) {
		size_t begin = subProbs[end].topK[0].edge;
		domains.push_back({begin+1, end});
		end = begin;
	}

    sort(domains.begin(), domains.end());

	return domains;
}
<commit_msg>Minor printout modifications to compare against new DP<commit_after>/*
    Authors: Darya Filippova, Geet Duggal, Rob Patro
    dfilippo | geet | robp @cs.cmu.edu
*/

#include <limits>
#include <boost/heap/binomial_heap.hpp>
#include <boost/range/irange.hpp>
#include <algorithm>
#include "ArmatusDAG.hpp"

ArmatusDAG::ArmatusDAG(ArmatusParams& p) :
	subProbs(SubProbsVec(p.n)),
    edgeWeights(EdgeWeightsVec(p.n, vector<double>())) {
	params = &p;
}

void ArmatusDAG::build() {
	// Since building the DAG visits everything in the same order as computing
	// a single optimial solution, I've had this function also fill out the
	// necessary information to obtain a backtrace of the opt. sln.
	subProbs[0].topK.push_back({std::numeric_limits<size_t>::max(), 0, 0.0});
	// What's the right condition here?
	// subProbs[1].topK.push_back({0, 0, std::max(q(0,1), 0.0)});

    for (size_t l : boost::irange(size_t{1}, params->n)) {
        // was this
  	    // edgeWeights[l].resize(l-1);
        // now this
  	    edgeWeights[l].resize(l);
  	    size_t chosenEdge = 0;
  	    double bestScore = 0.0;
  	    for (size_t k : boost::irange(size_t{0}, l)) {
  	    	// The last domain is [k,l]
  	    	double edgeWeight = std::max(q(k, l), 0.0);
            edgeWeights[l][k] = edgeWeight;
            double totalScore = edgeWeight;
            bool isDomain = edgeWeight > 0.0;
            bool isPrevDomain = (k == 0) ? true : false;
            if (k > 0) {
                double prevDomainScore = subProbs[k-1].topK[0].score;
                isPrevDomain = prevDomainScore > 0.0;
                // The score of this solution is the benefit we get from traversing
                // the edge + the best score available at the child
                totalScore += prevDomainScore;
             }
             if (isDomain or isPrevDomain) {
                 if (totalScore > bestScore) {
                     bestScore = totalScore;
                     chosenEdge = k;
                 }
            }
  	    }

  	    // Put our best solution on the stack.
  	    subProbs[l].topK.push_back({chosenEdge, 0, bestScore});
        cout << "OPTIMAL SCORE: " << bestScore << endl;
    }
}

double ArmatusDAG::s(size_t k, size_t l) {
	size_t d = l-k+1;
    return params->sums(k, l)/ std::pow(static_cast<double>(d),params->gamma);
}

double ArmatusDAG::q(size_t k, size_t l) {
	size_t d = l-k+1;
	return (s(k, l) - params->mu[d]);
}

/**
*  This interface is *wrong* but I wanted to sketch the
*  basic algo.
**/
void ArmatusDAG::computeTopK(uint32_t k) {
    for (size_t l : boost::irange(size_t{1}, params->n)) {
        std::function<bool (const BackPointer&, const BackPointer&)> BackPointerComparator = [l, this] (const BackPointer& x, const BackPointer& y) -> bool {
            auto scoreX = this->edgeWeights[l][x.edge];
            if (x.edge > 0) { scoreX += this->subProbs[x.edge-1].topK[x.childSolution].score; }
            auto scoreY = this->edgeWeights[l][y.edge];
            if (y.edge > 0) { scoreY += this->subProbs[y.edge-1].topK[y.childSolution].score; }

            return scoreX < scoreY;
        };

        boost::heap::binomial_heap<BackPointer,
            boost::heap::compare<decltype(BackPointerComparator)>> pq(BackPointerComparator);
        for (size_t j : boost::irange(size_t{0}, l)) {
            if (j > 0) {
                size_t i = j - 1;
                bool isDomain = edgeWeights[l][j] > 0.0;
                bool prevIsDomain = (subProbs[i].topK.size() > 0 and edgeWeights[i].size() > 0) ? edgeWeights[i][subProbs[i].topK[0].edge] > 0 : true;
                if (j == 1) { prevIsDomain = false; }

                if (isDomain or prevIsDomain) {
                    double score = edgeWeights[l][j] + subProbs[i].topK[0].score;
                    pq.push({j, 0, score});
                }
            } else {
                double score = edgeWeights[l][0];
                pq.push({0, 0, score});
            }
        }

        while (subProbs[l].topK.size() < k and !pq.empty()) {
            auto bp = pq.top();
            pq.pop();
            size_t j = bp.edge;
            if (j > 0) {
                bool alreadyFound{false};
                if (bp != subProbs[l].topK[0] ) { subProbs[l].topK.push_back(bp); }
                size_t nextSlnIdx = bp.childSolution + 1;
                bool isDomain = edgeWeights[l][j] > 0.0;

                size_t i = j - 1;
                //std::cout << bp.edge << "\t" << subProbs.size() << endl;
                if (nextSlnIdx < subProbs[i].topK.size()) {
                    bool prevIsDomain = edgeWeights[i][subProbs[i].topK[nextSlnIdx].edge] > 0.0;
                    if (isDomain or prevIsDomain ) {
                        double score = edgeWeights[l][j] + subProbs[i].topK[nextSlnIdx].score;
                        pq.push({j, nextSlnIdx, score});
                    }
                }
            } else {
                if (bp != subProbs[l].topK[0] ) { subProbs[l].topK.push_back(bp); }
            }
        }
    }

    // size_t sln = 0;
    // while (sln < k and sln < subProbs[params->n-1].topK.size()) {
    // 	std::cerr << "solution " << sln << " has score " << subProbs[params->n-1].topK[sln].score << "\n";
    // 	++sln;
    // }
}

WeightedDomainEnsemble ArmatusDAG::extractTopK(uint32_t k) {

  const size_t INVALID = std::numeric_limits<size_t>::max();
  // We skip 0 since that was already extracted by viterbiPath
  uint32_t currSln{0};

  WeightedDomainEnsemble solutions{ DomainEnsemble(k, DomainSet()), Weights(k, 0.0) };
  auto root = params->n-1;
  auto topScore = subProbs[root].topK[0].score;
  auto scores = Weights(k, 0.0);

  while (currSln < k and currSln < subProbs[root].topK.size()) {
    auto currentScore = subProbs[root].topK[currSln].score;
    scores[currSln] = currentScore;
    auto& currentDomainSet = solutions.domainSets[currSln];
    solutions.weights[currSln] = currentScore / topScore;

    // Which solution to use at the child
    auto bp = currSln;
    int64_t end = params->n-1;
    bool prevWasDomain = true;
    bool done{false};
    Domain prevDomain(root, root);

    while (end > 0) { // and subProbs[end].topK[bp].edge != INVALID) {
      //std::cerr << "end: " << end << "\n";
      size_t begin = subProbs[end].topK[bp].edge;
      size_t start = begin;
//      if (subProbs[begin].topK[subProbs[end].topK[bp].childSolution].edge != INVALID)
//         start++;
      Domain d(start, end);
      if (d.score(*params) > 0.0){
         currentDomainSet.push_back(d);
         prevWasDomain = true;
      } else {
         //currentDomainSet.push_back(d);
        if (!prevWasDomain) {
                std::cerr << "WHAT: solution contained two adjacent non-domains; current domain is (" << start << ", " << end << ") prev domain was (" << prevDomain.start << ", " << prevDomain.end << ")\n";
        }
        prevWasDomain = false;
      }
      prevDomain = d;
      bp = subProbs[end].topK[bp].childSolution;
      end = begin-1;
   }

    ++currSln;
  }

  /**
   * consistency check all the extracted domains (for debug purposes only,
   * take this out for release / speed).
   */
  size_t c = 0;
  double eps = 1e-3;
  for (auto& ds : solutions.domainSets) {
    double score = 0.0;
    for (auto& d : ds) {
      score += d.score(*params);
    }
    if (std::abs(score - scores[c]) > eps) {
      std::cerr << "For solution [" << c << "], the recorded score was " << scores[c] << " but extracted domains sum to " << score << "\n";
    }
    ++c;
  }

  return solutions;
}

vector<Domain> ArmatusDAG::viterbiPath() {
	vector<Domain> domains;
  const size_t INVALID = std::numeric_limits<size_t>::max();
	size_t end = params->n-1;
	//std::cerr << "Best score is " << subProbs[end].topK[0].score << "\n";

	while (subProbs[end].topK[0].edge != INVALID) {
		size_t begin = subProbs[end].topK[0].edge;
		domains.push_back({begin+1, end});
		end = begin;
	}

    sort(domains.begin(), domains.end());

	return domains;
}
<|endoftext|>


<commit_before>// ArrowButton.cc for Fluxbox Window Manager
// Copyright (c) 2002-2003 Henrik Kinnunen (fluxgen at users.sourceforge.net)
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

// $Id: ArrowButton.cc,v 1.9 2004/09/12 14:56:18 rathnor Exp $

#include "ArrowButton.hh"
#include "ButtonTheme.hh"

ArrowButton::ArrowButton(ArrowButton::Type arrow_type,
                         const FbTk::FbWindow &parent,
                         int x, int y,
                         unsigned int width, unsigned int height):
    FbTk::Button(parent, x, y, width, height),
    m_arrow_type(arrow_type),
    m_mouse_handler(0),
    m_arrowscale(300) {

    setEventMask(ExposureMask | ButtonPressMask | ButtonReleaseMask |
                 EnterWindowMask | LeaveWindowMask);
}

ArrowButton::ArrowButton(ArrowButton::Type arrow_type,
                         int screen_num,
                         int x, int y,
                         unsigned int width, unsigned int height):
    FbTk::Button(screen_num, x, y, width, height),
    m_arrow_type(arrow_type),
    m_mouse_handler(0),
    m_arrowscale(300) {

    setEventMask(ExposureMask | ButtonPressMask | ButtonReleaseMask |
                 EnterWindowMask | LeaveWindowMask);
}

void ArrowButton::clear() {
    FbTk::Button::clear();
    updateTransparent();
    drawArrow();
}

void ArrowButton::exposeEvent(XExposeEvent &event) {
    FbTk::Button::exposeEvent(event);
    updateTransparent(event.x, event.y, event.width, event.height);
    drawArrow();
}

void ArrowButton::buttonPressEvent(XButtonEvent &event) {
    FbTk::Button::buttonPressEvent(event);
    drawArrow();
}

void ArrowButton::buttonReleaseEvent(XButtonEvent &event) {
    FbTk::Button::buttonReleaseEvent(event);
    drawArrow();
}

void ArrowButton::enterNotifyEvent(XCrossingEvent &ce) {
    if (m_mouse_handler)
	m_mouse_handler->enterNotifyEvent(ce);
}

void ArrowButton::leaveNotifyEvent(XCrossingEvent &ce) {
    if (m_mouse_handler)
	m_mouse_handler->leaveNotifyEvent(ce);
}

/**
 redraws the arrow button
*/
void ArrowButton::drawArrow() {
    XPoint pts[3];
    unsigned int w = width();
    unsigned int h = height();

    int arrowscale_n = m_arrowscale;
    int arrowscale_d = 100;
    unsigned int ax = arrowscale_d * w / arrowscale_n;
    unsigned int ay = arrowscale_d * h / arrowscale_n;
    // if these aren't an even number, left and right arrows end up different
    if (( ax % 2 ) == 1) ax++;
    if (( ay % 2 ) == 1) ay++;
    switch (m_arrow_type) {
    case LEFT:
		// start at the tip
        pts[0].x = (w / 2) - (ax / 2); pts[0].y = h / 2;
        pts[1].x = ax; pts[1].y = -ay / 2;
        pts[2].x = 0; pts[2].y = ay;
        break;
    case RIGHT:
        pts[0].x = (w / 2) + (ax / 2); pts[0].y = h / 2;
        pts[1].x = - ax; pts[1].y = ay / 2;
        pts[2].x = 0; pts[2].y = - ay;
        break;
    case UP:
        pts[0].x = (w / 2); pts[0].y = (h / 2) - (ay / 2);
        pts[1].x = ax / 2; pts[1].y = ay;
        pts[2].x = - ax; pts[2].y = 0;
        break;
    case DOWN:
        pts[0].x = (w / 2); pts[0].y = (h / 2) + (ay / 2);
        pts[1].x = ax / 2; pts[1].y = - ay;
        pts[2].x = - ax; pts[2].y = 0;
        break;
    }

    if (gc() != 0) {
        fillPolygon(gc(),
                    pts, 3,
                    Convex, CoordModePrevious);
    }
}

void ArrowButton::updateTheme(const FbTk::Theme &theme) {
    // it must be a button theme
    const ButtonTheme &btheme = static_cast<const ButtonTheme &>(theme);

    m_arrowscale = btheme.scale();
    if (m_arrowscale == 0) m_arrowscale = 300; // default is 0 => 300
    else if (m_arrowscale < 100) m_arrowscale = 100; // otherwise clamp
    else if (m_arrowscale > 100000) m_arrowscale = 100000; // clamp below overflow when *100
}
<commit_msg>fix:<commit_after>// ArrowButton.cc for Fluxbox Window Manager
// Copyright (c) 2002-2003 Henrik Kinnunen (fluxgen at users.sourceforge.net)
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

// $Id: ArrowButton.cc,v 1.10 2004/10/21 11:05:06 akir Exp $

#include "ArrowButton.hh"
#include "FbTk/ThemeItems.hh"
#include "ButtonTheme.hh"

ArrowButton::ArrowButton(ArrowButton::Type arrow_type,
                         const FbTk::FbWindow &parent,
                         int x, int y,
                         unsigned int width, unsigned int height):
    FbTk::Button(parent, x, y, width, height),
    m_arrow_type(arrow_type),
    m_mouse_handler(0),
    m_arrowscale(300) {

    setEventMask(ExposureMask | ButtonPressMask | ButtonReleaseMask |
                 EnterWindowMask | LeaveWindowMask);
}

ArrowButton::ArrowButton(ArrowButton::Type arrow_type,
                         int screen_num,
                         int x, int y,
                         unsigned int width, unsigned int height):
    FbTk::Button(screen_num, x, y, width, height),
    m_arrow_type(arrow_type),
    m_mouse_handler(0),
    m_arrowscale(300) {

    setEventMask(ExposureMask | ButtonPressMask | ButtonReleaseMask |
                 EnterWindowMask | LeaveWindowMask);
}

void ArrowButton::clear() {
    FbTk::Button::clear();
    updateTransparent();
    drawArrow();
}

void ArrowButton::exposeEvent(XExposeEvent &event) {
    FbTk::Button::exposeEvent(event);
    updateTransparent(event.x, event.y, event.width, event.height);
    drawArrow();
}

void ArrowButton::buttonPressEvent(XButtonEvent &event) {
    FbTk::Button::buttonPressEvent(event);
    drawArrow();
}

void ArrowButton::buttonReleaseEvent(XButtonEvent &event) {
    FbTk::Button::buttonReleaseEvent(event);
    drawArrow();
}

void ArrowButton::enterNotifyEvent(XCrossingEvent &ce) {
    if (m_mouse_handler)
	m_mouse_handler->enterNotifyEvent(ce);
}

void ArrowButton::leaveNotifyEvent(XCrossingEvent &ce) {
    if (m_mouse_handler)
	m_mouse_handler->leaveNotifyEvent(ce);
}

/**
 redraws the arrow button
*/
void ArrowButton::drawArrow() {
    XPoint pts[3];
    unsigned int w = width();
    unsigned int h = height();

    int arrowscale_n = m_arrowscale;
    int arrowscale_d = 100;
    unsigned int ax = arrowscale_d * w / arrowscale_n;
    unsigned int ay = arrowscale_d * h / arrowscale_n;
    // if these aren't an even number, left and right arrows end up different
    if (( ax % 2 ) == 1) ax++;
    if (( ay % 2 ) == 1) ay++;
    switch (m_arrow_type) {
    case LEFT:
		// start at the tip
        pts[0].x = (w / 2) - (ax / 2); pts[0].y = h / 2;
        pts[1].x = ax; pts[1].y = -ay / 2;
        pts[2].x = 0; pts[2].y = ay;
        break;
    case RIGHT:
        pts[0].x = (w / 2) + (ax / 2); pts[0].y = h / 2;
        pts[1].x = - ax; pts[1].y = ay / 2;
        pts[2].x = 0; pts[2].y = - ay;
        break;
    case UP:
        pts[0].x = (w / 2); pts[0].y = (h / 2) - (ay / 2);
        pts[1].x = ax / 2; pts[1].y = ay;
        pts[2].x = - ax; pts[2].y = 0;
        break;
    case DOWN:
        pts[0].x = (w / 2); pts[0].y = (h / 2) + (ay / 2);
        pts[1].x = ax / 2; pts[1].y = - ay;
        pts[2].x = - ax; pts[2].y = 0;
        break;
    }

    if (gc() != 0) {
        fillPolygon(gc(),
                    pts, 3,
                    Convex, CoordModePrevious);
    }
}

void ArrowButton::updateTheme(const FbTk::Theme &theme) {
    // it must be a button theme
    const ButtonTheme &btheme = static_cast<const ButtonTheme &>(theme);

    m_arrowscale = btheme.scale();
    if (m_arrowscale == 0) m_arrowscale = 300; // default is 0 => 300
    else if (m_arrowscale < 100) m_arrowscale = 100; // otherwise clamp
    else if (m_arrowscale > 100000) m_arrowscale = 100000; // clamp below overflow when *100
}
<|endoftext|>


<commit_before>///
// This file is part of the Marble Virtual Globe.
//
// This program is free software licensed under the GNU LGPL. You can
// find a copy of this license in LICENSE.txt in the top directory of
// the source code.
//
// Copyright 2004-2007 Torsten Rahn  <tackat@kde.org>
// Copyright 2007      Inge Wallin   <ingwa@kde.org>
// Copyright 2007      Thomas Zander <zander@kde.org>
// Copyright 2010      Bastian Holst <bastianholst@gmx.de>
//

// Self
#include "NavigationWidget.h"

// Marble
#include "MarbleDebug.h"
#include "MarbleModel.h"
#include "MarbleWidget.h"
#include "MarbleRunnerManager.h"
#include "MarblePlacemarkModel.h"
#include "GeoDataDocument.h"
#include "GeoDataTreeModel.h"
#include "GeoSceneDocument.h"
#include "GeoSceneHead.h"

// Qt
#include <QtCore/QTime>
#include <QtCore/QTimer>
#include <QtGui/QSortFilterProxyModel>

using namespace Marble;

#include "ui_NavigationWidget.h"

namespace Marble
{

class NavigationWidgetPrivate
{
 public:
    Ui::NavigationWidget    m_navigationUi;
    MarbleWidget           *m_widget;
    QSortFilterProxyModel  *m_sortproxy;
    QString                 m_searchTerm;
    MarbleRunnerManager    *m_runnerManager;
    QTimer                  m_deferSearch;
    GeoDataTreeModel        m_treeModel;
    GeoDataDocument        *m_document;

    NavigationWidgetPrivate()
        : m_document( new GeoDataDocument ) {
    m_document->setDocumentRole( SearchResultDocument );
    m_treeModel.setRootDocument( m_document );
    };

};

NavigationWidget::NavigationWidget( QWidget *parent, Qt::WindowFlags f )
    : QWidget( parent, f ),
      d( new NavigationWidgetPrivate() )
{
    d->m_searchTerm.clear();
    d->m_widget = 0;

    d->m_navigationUi.setupUi( this );

    d->m_sortproxy = new QSortFilterProxyModel( this );
    d->m_navigationUi.locationListView->setModel( d->m_sortproxy );
    d->m_deferSearch.setSingleShot( true );
    connect ( &d->m_deferSearch, SIGNAL( timeout() ),
              this, SLOT( search()) );

    connect( d->m_navigationUi.goHomeButton,     SIGNAL( clicked() ),
             this,                               SIGNAL( goHome() ) );
    connect( d->m_navigationUi.zoomSlider,       SIGNAL( valueChanged( int ) ),
             this,                               SIGNAL( zoomChanged( int ) ) );
    connect( d->m_navigationUi.zoomInButton,     SIGNAL( clicked() ),
             this,                               SIGNAL( zoomIn() ) );
    connect( d->m_navigationUi.zoomOutButton,    SIGNAL( clicked() ),
             this,                               SIGNAL( zoomOut() ) );

    connect( d->m_navigationUi.zoomSlider,       SIGNAL( valueChanged( int ) ),
             this,                               SLOT( updateButtons( int ) ) );

    connect( d->m_navigationUi.moveLeftButton,   SIGNAL( clicked() ),
             this,                               SIGNAL( moveLeft() ) );
    connect( d->m_navigationUi.moveRightButton,  SIGNAL( clicked() ),
             this,                               SIGNAL( moveRight() ) );
    connect( d->m_navigationUi.moveUpButton,     SIGNAL( clicked() ),
             this,                               SIGNAL( moveUp() ) );
    connect( d->m_navigationUi.moveDownButton,   SIGNAL( clicked() ),
             this,                               SIGNAL( moveDown() ) );

    connect( d->m_navigationUi.locationListView, SIGNAL( activated( const QModelIndex& ) ),
             this,                               SLOT( mapCenterOnSignal( const QModelIndex& ) ) );

    connect( d->m_navigationUi.searchLineEdit,   SIGNAL( textChanged( const QString& ) ),
             this,                               SLOT( searchLineChanged( const QString& ) ) );
    connect( d->m_navigationUi.searchLineEdit,   SIGNAL( returnPressed() ),
             this,                               SLOT( searchReturnPressed() ) );

    connect( d->m_navigationUi.zoomSlider,       SIGNAL( sliderPressed() ),
             this,                               SLOT( adjustForAnimation() ) );
    connect( d->m_navigationUi.zoomSlider,       SIGNAL( sliderReleased() ),
             this,                               SLOT( adjustForStill() ) );
}

NavigationWidget::~NavigationWidget()
{
    delete d;
}

void NavigationWidget::setMarbleWidget( MarbleWidget *widget )
{
    d->m_runnerManager = new MarbleRunnerManager( widget->model()->pluginManager(), this );
    connect( d->m_runnerManager, SIGNAL( searchResultChanged( QVector<GeoDataPlacemark*> ) ),
             this,               SLOT( setLocations( QVector<GeoDataPlacemark*> ) ) );

    d->m_widget = widget;
    d->m_runnerManager->setModel( widget->model() );
    d->m_widget->model()->treeModel()->addDocument( d->m_document );

    d->m_sortproxy->setSortLocaleAware( true );
    d->m_sortproxy->setDynamicSortFilter( true );

    // Make us aware of all the Placemarks in the MarbleModel so that
    // we can search them.
    d->m_sortproxy->setSourceModel( d->m_widget->model()->placemarkModel() );
    d->m_sortproxy->sort( 0 );

    // Connect necessary signals.
    connect( this, SIGNAL( goHome() ),         d->m_widget, SLOT( goHome() ) );
    connect( this, SIGNAL( zoomChanged(int) ), d->m_widget, SLOT( zoomView( int ) ) );
    connect( this, SIGNAL( zoomIn() ),         d->m_widget, SLOT( zoomIn() ) );
    connect( this, SIGNAL( zoomOut() ),        d->m_widget, SLOT( zoomOut() ) );

    connect( this, SIGNAL( moveLeft() ),  d->m_widget, SLOT( moveLeft() ) );
    connect( this, SIGNAL( moveRight() ), d->m_widget, SLOT( moveRight() ) );
    connect( this, SIGNAL( moveUp() ),    d->m_widget, SLOT( moveUp() ) );
    connect( this, SIGNAL( moveDown() ),  d->m_widget, SLOT( moveDown() ) );

    connect( d->m_widget, SIGNAL( zoomChanged( int ) ),
             this,        SLOT( changeZoom( int ) ) );

    connect( d->m_widget, SIGNAL( themeChanged( QString ) ),
             this,        SLOT( selectTheme( QString ) ) );
}

void NavigationWidget::changeZoom( int zoom )
{
    // There exists a circular signal/slot connection between MarbleWidget and this widget's
    // zoom slider. MarbleWidget prevents recursion, but it still loops one time unless
    // blocked here. Note that it would be possible to only connect the sliders
    // sliderMoved signal instead of its valueChanged signal above to break up the loop.
    // This however means that the slider cannot be operated with the mouse wheel, as this
    // does not emit the sliderMoved signal for some reason. Therefore the signal is blocked
    // below before calling setValue on the slider to avoid that it calls back to MarbleWidget,
    // and then un-blocked again to make user interaction possible.

    d->m_navigationUi.zoomSlider->blockSignals( true );

    d->m_navigationUi.zoomSlider->setValue( zoom );
    // As we have disabled all zoomSlider Signals, we have to update our buttons seperately.
    updateButtons( zoom );

    d->m_navigationUi.zoomSlider->blockSignals( false );
}

void NavigationWidget::searchLineChanged( const QString &search )
{
    d->m_searchTerm = search;
    // if search line is empty, restore original geonames
    if ( d->m_searchTerm.isEmpty() ) {
        // set the proxy list to the placemarkModel
        d->m_sortproxy->setSourceModel( d->m_widget->model()->placemarkModel() );
        d->m_sortproxy->sort( 0 );
        d->m_widget->model()->placemarkSelectionModel()->clear();

        // clear the local document
        d->m_widget->model()->treeModel()->removeDocument( d->m_document );
        d->m_document->clear();
        d->m_widget->model()->treeModel()->addDocument( d->m_document );
    }
    d->m_deferSearch.start( 500 );
}

void NavigationWidget::searchReturnPressed()
{
    // do nothing if search term empty
    if ( !d->m_searchTerm.isEmpty() ) {
        d->m_runnerManager->findPlacemarks( d->m_searchTerm );
    }
}

void NavigationWidget::search()
{
    d->m_deferSearch.stop();
    int  currentSelected = d->m_navigationUi.locationListView->currentIndex().row();
    d->m_navigationUi.locationListView->selectItem( d->m_searchTerm );
    if ( currentSelected != d->m_navigationUi.locationListView->currentIndex().row() )
        d->m_navigationUi.locationListView->activate();
}

void NavigationWidget::setLocations( QVector<GeoDataPlacemark*> locations )
{
    QTime t;
    t.start();

    // fill the local document with results
    d->m_widget->model()->placemarkSelectionModel()->clear();
    d->m_widget->model()->treeModel()->removeDocument( d->m_document );
    d->m_document->clear();
    foreach (GeoDataPlacemark *placemark, locations ) {
        d->m_document->append( new GeoDataPlacemark( *placemark ) );
    }
    d->m_widget->model()->treeModel()->addDocument( d->m_document );

    // set the proxy list to the list of results
    d->m_sortproxy->setSourceModel( &d->m_treeModel );
    d->m_sortproxy->sort( 0 );
    mDebug() << "NavigationWidget (sort): Time elapsed:"<< t.elapsed() << " ms";
}

void NavigationWidget::selectTheme( const QString &theme )
{
    Q_UNUSED( theme )

    if( !d->m_widget )
        return;

    d->m_navigationUi.zoomSlider->setMinimum( d->m_widget->minimumZoom() );
    d->m_navigationUi.zoomSlider->setMaximum( d->m_widget->maximumZoom() );
    updateButtons( d->m_navigationUi.zoomSlider->value() );
}

void NavigationWidget::updateButtons( int value )
{
    if ( value <= d->m_navigationUi.zoomSlider->minimum() ) {
        d->m_navigationUi.zoomInButton->setEnabled( true );
        d->m_navigationUi.zoomOutButton->setEnabled( false );
    } else if ( value >= d->m_navigationUi.zoomSlider->maximum() ) {
        d->m_navigationUi.zoomInButton->setEnabled( false );
        d->m_navigationUi.zoomOutButton->setEnabled( true );
    } else {
        d->m_navigationUi.zoomInButton->setEnabled( true );
        d->m_navigationUi.zoomOutButton->setEnabled( true );
    }
}

void NavigationWidget::mapCenterOnSignal( const QModelIndex &index )
{
    if( !index.isValid() ) {
        return;
    }
    GeoDataObject *object
            = qVariantValue<GeoDataObject*>( index.model()->data(index, MarblePlacemarkModel::ObjectPointerRole ) );
    if ( dynamic_cast<GeoDataPlacemark*>(object) )
    {
        GeoDataPlacemark *placemark = static_cast<GeoDataPlacemark*>(object);
        d->m_widget->centerOn( *placemark, true );
        d->m_widget->model()->placemarkSelectionModel()->select( d->m_sortproxy->mapToSource( index ), QItemSelectionModel::ClearAndSelect );
    }
}

void NavigationWidget::adjustForAnimation()
{
    // TODO: use signals here as well
    if ( !d->m_widget )
        return;

    d->m_widget->setViewContext( Animation );
}

void NavigationWidget::adjustForStill()
{
    // TODO: use signals here as well
    if ( !d->m_widget )
        return;

    d->m_widget->setViewContext( Still );
}

void NavigationWidget::resizeEvent ( QResizeEvent * )
{
    bool smallScreen = MarbleGlobal::getInstance()->profiles() & MarbleGlobal::SmallScreen;

    if ( smallScreen || height() < 390 ) {
        if ( !d->m_navigationUi.zoomSlider->isHidden() ) {
            setUpdatesEnabled(false);
            d->m_navigationUi.zoomSlider->hide();
            d->m_navigationUi.m_pSpacerFrame->setSizePolicy( QSizePolicy::Preferred,
                                                             QSizePolicy::Expanding );
            setUpdatesEnabled(true);
        }
    } else {
        if ( d->m_navigationUi.zoomSlider->isHidden() ) {
            setUpdatesEnabled(false);
            d->m_navigationUi.zoomSlider->show();
            d->m_navigationUi.m_pSpacerFrame->setSizePolicy( QSizePolicy::Preferred,
                                                       QSizePolicy::Fixed );
            setUpdatesEnabled(true);
        }
    }
}

}

#include "NavigationWidget.moc"
<commit_msg>NavigationWidget: recenter on search results<commit_after>///
// This file is part of the Marble Virtual Globe.
//
// This program is free software licensed under the GNU LGPL. You can
// find a copy of this license in LICENSE.txt in the top directory of
// the source code.
//
// Copyright 2004-2007 Torsten Rahn  <tackat@kde.org>
// Copyright 2007      Inge Wallin   <ingwa@kde.org>
// Copyright 2007      Thomas Zander <zander@kde.org>
// Copyright 2010      Bastian Holst <bastianholst@gmx.de>
//

// Self
#include "NavigationWidget.h"

// Marble
#include "MarbleDebug.h"
#include "MarbleModel.h"
#include "MarbleWidget.h"
#include "MarbleRunnerManager.h"
#include "MarblePlacemarkModel.h"
#include "GeoDataDocument.h"
#include "GeoDataTreeModel.h"
#include "GeoSceneDocument.h"
#include "GeoSceneHead.h"

// Qt
#include <QtCore/QTime>
#include <QtCore/QTimer>
#include <QtGui/QSortFilterProxyModel>

using namespace Marble;

#include "ui_NavigationWidget.h"

namespace Marble
{

class NavigationWidgetPrivate
{
 public:
    Ui::NavigationWidget    m_navigationUi;
    MarbleWidget           *m_widget;
    QSortFilterProxyModel  *m_sortproxy;
    QString                 m_searchTerm;
    MarbleRunnerManager    *m_runnerManager;
    QTimer                  m_deferSearch;
    GeoDataTreeModel        m_treeModel;
    GeoDataDocument        *m_document;

    NavigationWidgetPrivate()
        : m_document( new GeoDataDocument ) {
    m_document->setDocumentRole( SearchResultDocument );
    m_treeModel.setRootDocument( m_document );
    };

};

NavigationWidget::NavigationWidget( QWidget *parent, Qt::WindowFlags f )
    : QWidget( parent, f ),
      d( new NavigationWidgetPrivate() )
{
    d->m_searchTerm.clear();
    d->m_widget = 0;

    d->m_navigationUi.setupUi( this );

    d->m_sortproxy = new QSortFilterProxyModel( this );
    d->m_navigationUi.locationListView->setModel( d->m_sortproxy );
    d->m_deferSearch.setSingleShot( true );
    connect ( &d->m_deferSearch, SIGNAL( timeout() ),
              this, SLOT( search()) );

    connect( d->m_navigationUi.goHomeButton,     SIGNAL( clicked() ),
             this,                               SIGNAL( goHome() ) );
    connect( d->m_navigationUi.zoomSlider,       SIGNAL( valueChanged( int ) ),
             this,                               SIGNAL( zoomChanged( int ) ) );
    connect( d->m_navigationUi.zoomInButton,     SIGNAL( clicked() ),
             this,                               SIGNAL( zoomIn() ) );
    connect( d->m_navigationUi.zoomOutButton,    SIGNAL( clicked() ),
             this,                               SIGNAL( zoomOut() ) );

    connect( d->m_navigationUi.zoomSlider,       SIGNAL( valueChanged( int ) ),
             this,                               SLOT( updateButtons( int ) ) );

    connect( d->m_navigationUi.moveLeftButton,   SIGNAL( clicked() ),
             this,                               SIGNAL( moveLeft() ) );
    connect( d->m_navigationUi.moveRightButton,  SIGNAL( clicked() ),
             this,                               SIGNAL( moveRight() ) );
    connect( d->m_navigationUi.moveUpButton,     SIGNAL( clicked() ),
             this,                               SIGNAL( moveUp() ) );
    connect( d->m_navigationUi.moveDownButton,   SIGNAL( clicked() ),
             this,                               SIGNAL( moveDown() ) );

    connect( d->m_navigationUi.locationListView, SIGNAL( activated( const QModelIndex& ) ),
             this,                               SLOT( mapCenterOnSignal( const QModelIndex& ) ) );

    connect( d->m_navigationUi.searchLineEdit,   SIGNAL( textChanged( const QString& ) ),
             this,                               SLOT( searchLineChanged( const QString& ) ) );
    connect( d->m_navigationUi.searchLineEdit,   SIGNAL( returnPressed() ),
             this,                               SLOT( searchReturnPressed() ) );

    connect( d->m_navigationUi.zoomSlider,       SIGNAL( sliderPressed() ),
             this,                               SLOT( adjustForAnimation() ) );
    connect( d->m_navigationUi.zoomSlider,       SIGNAL( sliderReleased() ),
             this,                               SLOT( adjustForStill() ) );
}

NavigationWidget::~NavigationWidget()
{
    delete d;
}

void NavigationWidget::setMarbleWidget( MarbleWidget *widget )
{
    d->m_runnerManager = new MarbleRunnerManager( widget->model()->pluginManager(), this );
    connect( d->m_runnerManager, SIGNAL( searchResultChanged( QVector<GeoDataPlacemark*> ) ),
             this,               SLOT( setLocations( QVector<GeoDataPlacemark*> ) ) );

    d->m_widget = widget;
    d->m_runnerManager->setModel( widget->model() );
    d->m_widget->model()->treeModel()->addDocument( d->m_document );

    d->m_sortproxy->setSortLocaleAware( true );
    d->m_sortproxy->setDynamicSortFilter( true );

    // Make us aware of all the Placemarks in the MarbleModel so that
    // we can search them.
    d->m_sortproxy->setSourceModel( d->m_widget->model()->placemarkModel() );
    d->m_sortproxy->sort( 0 );

    // Connect necessary signals.
    connect( this, SIGNAL( goHome() ),         d->m_widget, SLOT( goHome() ) );
    connect( this, SIGNAL( zoomChanged(int) ), d->m_widget, SLOT( zoomView( int ) ) );
    connect( this, SIGNAL( zoomIn() ),         d->m_widget, SLOT( zoomIn() ) );
    connect( this, SIGNAL( zoomOut() ),        d->m_widget, SLOT( zoomOut() ) );

    connect( this, SIGNAL( moveLeft() ),  d->m_widget, SLOT( moveLeft() ) );
    connect( this, SIGNAL( moveRight() ), d->m_widget, SLOT( moveRight() ) );
    connect( this, SIGNAL( moveUp() ),    d->m_widget, SLOT( moveUp() ) );
    connect( this, SIGNAL( moveDown() ),  d->m_widget, SLOT( moveDown() ) );

    connect( d->m_widget, SIGNAL( zoomChanged( int ) ),
             this,        SLOT( changeZoom( int ) ) );

    connect( d->m_widget, SIGNAL( themeChanged( QString ) ),
             this,        SLOT( selectTheme( QString ) ) );
}

void NavigationWidget::changeZoom( int zoom )
{
    // There exists a circular signal/slot connection between MarbleWidget and this widget's
    // zoom slider. MarbleWidget prevents recursion, but it still loops one time unless
    // blocked here. Note that it would be possible to only connect the sliders
    // sliderMoved signal instead of its valueChanged signal above to break up the loop.
    // This however means that the slider cannot be operated with the mouse wheel, as this
    // does not emit the sliderMoved signal for some reason. Therefore the signal is blocked
    // below before calling setValue on the slider to avoid that it calls back to MarbleWidget,
    // and then un-blocked again to make user interaction possible.

    d->m_navigationUi.zoomSlider->blockSignals( true );

    d->m_navigationUi.zoomSlider->setValue( zoom );
    // As we have disabled all zoomSlider Signals, we have to update our buttons seperately.
    updateButtons( zoom );

    d->m_navigationUi.zoomSlider->blockSignals( false );
}

void NavigationWidget::searchLineChanged( const QString &search )
{
    d->m_searchTerm = search;
    // if search line is empty, restore original geonames
    if ( d->m_searchTerm.isEmpty() ) {
        // set the proxy list to the placemarkModel
        d->m_sortproxy->setSourceModel( d->m_widget->model()->placemarkModel() );
        d->m_sortproxy->sort( 0 );
        d->m_widget->model()->placemarkSelectionModel()->clear();

        // clear the local document
        d->m_widget->model()->treeModel()->removeDocument( d->m_document );
        d->m_document->clear();
        d->m_widget->model()->treeModel()->addDocument( d->m_document );
    }
    d->m_deferSearch.start( 500 );
}

void NavigationWidget::searchReturnPressed()
{
    // do nothing if search term empty
    if ( !d->m_searchTerm.isEmpty() ) {
        d->m_runnerManager->findPlacemarks( d->m_searchTerm );
    }
}

void NavigationWidget::search()
{
    d->m_deferSearch.stop();
    int  currentSelected = d->m_navigationUi.locationListView->currentIndex().row();
    d->m_navigationUi.locationListView->selectItem( d->m_searchTerm );
    if ( currentSelected != d->m_navigationUi.locationListView->currentIndex().row() )
        d->m_navigationUi.locationListView->activate();
}

void NavigationWidget::setLocations( QVector<GeoDataPlacemark*> locations )
{
    QTime t;
    t.start();

    // fill the local document with results
    d->m_widget->model()->placemarkSelectionModel()->clear();
    d->m_widget->model()->treeModel()->removeDocument( d->m_document );
    d->m_document->clear();
    foreach (GeoDataPlacemark *placemark, locations ) {
        d->m_document->append( new GeoDataPlacemark( *placemark ) );
    }
    d->m_widget->model()->treeModel()->addDocument( d->m_document );
    d->m_widget->centerOn( d->m_document->latLonAltBox() );

    // set the proxy list to the list of results
    d->m_sortproxy->setSourceModel( &d->m_treeModel );
    d->m_sortproxy->sort( 0 );
    mDebug() << "NavigationWidget (sort): Time elapsed:"<< t.elapsed() << " ms";
}

void NavigationWidget::selectTheme( const QString &theme )
{
    Q_UNUSED( theme )

    if( !d->m_widget )
        return;

    d->m_navigationUi.zoomSlider->setMinimum( d->m_widget->minimumZoom() );
    d->m_navigationUi.zoomSlider->setMaximum( d->m_widget->maximumZoom() );
    updateButtons( d->m_navigationUi.zoomSlider->value() );
}

void NavigationWidget::updateButtons( int value )
{
    if ( value <= d->m_navigationUi.zoomSlider->minimum() ) {
        d->m_navigationUi.zoomInButton->setEnabled( true );
        d->m_navigationUi.zoomOutButton->setEnabled( false );
    } else if ( value >= d->m_navigationUi.zoomSlider->maximum() ) {
        d->m_navigationUi.zoomInButton->setEnabled( false );
        d->m_navigationUi.zoomOutButton->setEnabled( true );
    } else {
        d->m_navigationUi.zoomInButton->setEnabled( true );
        d->m_navigationUi.zoomOutButton->setEnabled( true );
    }
}

void NavigationWidget::mapCenterOnSignal( const QModelIndex &index )
{
    if( !index.isValid() ) {
        return;
    }
    GeoDataObject *object
            = qVariantValue<GeoDataObject*>( index.model()->data(index, MarblePlacemarkModel::ObjectPointerRole ) );
    if ( dynamic_cast<GeoDataPlacemark*>(object) )
    {
        GeoDataPlacemark *placemark = static_cast<GeoDataPlacemark*>(object);
        d->m_widget->centerOn( *placemark, true );
        d->m_widget->model()->placemarkSelectionModel()->select( d->m_sortproxy->mapToSource( index ), QItemSelectionModel::ClearAndSelect );
    }
}

void NavigationWidget::adjustForAnimation()
{
    // TODO: use signals here as well
    if ( !d->m_widget )
        return;

    d->m_widget->setViewContext( Animation );
}

void NavigationWidget::adjustForStill()
{
    // TODO: use signals here as well
    if ( !d->m_widget )
        return;

    d->m_widget->setViewContext( Still );
}

void NavigationWidget::resizeEvent ( QResizeEvent * )
{
    bool smallScreen = MarbleGlobal::getInstance()->profiles() & MarbleGlobal::SmallScreen;

    if ( smallScreen || height() < 390 ) {
        if ( !d->m_navigationUi.zoomSlider->isHidden() ) {
            setUpdatesEnabled(false);
            d->m_navigationUi.zoomSlider->hide();
            d->m_navigationUi.m_pSpacerFrame->setSizePolicy( QSizePolicy::Preferred,
                                                             QSizePolicy::Expanding );
            setUpdatesEnabled(true);
        }
    } else {
        if ( d->m_navigationUi.zoomSlider->isHidden() ) {
            setUpdatesEnabled(false);
            d->m_navigationUi.zoomSlider->show();
            d->m_navigationUi.m_pSpacerFrame->setSizePolicy( QSizePolicy::Preferred,
                                                       QSizePolicy::Fixed );
            setUpdatesEnabled(true);
        }
    }
}

}

#include "NavigationWidget.moc"
<|endoftext|>