<commit_before>/*
 * LinkBasedFileLock.cpp
 *
 * Copyright (C) 2009-12 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include <core/FileLock.hpp>

#include <errno.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>

#include <set>
#include <vector>

#include <core/SafeConvert.hpp>
#include <core/Algorithm.hpp>
#include <core/Thread.hpp>
#include <core/Error.hpp>
#include <core/Log.hpp>
#include <core/FilePath.hpp>
#include <core/FileSerializer.hpp>
#include <core/system/Process.hpp>
#include <core/system/System.hpp>

#include <boost/foreach.hpp>
#include <boost/system/error_code.hpp>

#define LOG(__X__)                                                             \
   do                                                                          \
   {                                                                           \
      if (::rstudio::core::FileLock::isLoggingEnabled())                       \
      {                                                                        \
         std::stringstream ss;                                                 \
         ss << "(PID " << ::getpid() << "): " << __X__ << std::endl;           \
         ::rstudio::core::FileLock::log(ss.str());                             \
      }                                                                        \
   } while (0)

namespace rstudio {
namespace core {

namespace {

const char * const kFileLockPrefix =
      ".rstudio-lock-41c29";

std::string pidString()
{
   PidType pid = system::currentProcessId();
   return safe_convert::numberToString((long) pid);
}

std::string hostName()
{
   char buffer[256];
   int status = ::gethostname(buffer, 255);
   if (status)
      LOG_ERROR(systemError(errno, ERROR_LOCATION));
   return std::string(buffer);
}

std::string threadId()
{
   std::stringstream ss;
   ss << boost::this_thread::get_id();
   return ss.str();
}

std::string proxyLockFileName()
{
   return std::string()
         + kFileLockPrefix
         + "-" + hostName()
         + "-" + pidString()
         + "-" + threadId();

}

bool isLockFileStale(const FilePath& lockFilePath)
{
   return LinkBasedFileLock::isLockFileStale(lockFilePath);
}

bool isLockFileOrphaned(const FilePath& lockFilePath)
{
#ifndef _WIN32

   Error error;

   // attempt to read pid from lockfile
   std::string pid;
   error = core::readStringFromFile(lockFilePath, &pid);
   if (error)
   {
      LOG_ERROR(error);
      return false;
   }
   pid = string_utils::trimWhitespace(pid);

#ifdef __linux__

   // on linux, we can check the proc filesystem for an associated
   // process -- if there is no such directory, then we assume that
   // this lockfile has been orphaned
   FilePath procPath("/proc/" + pid);
   if (!procPath.exists())
      return true;

#endif

   // call 'ps' to attempt to see if a process associated
   // with this process id exists (and get information about it)
   using namespace core::system;
   std::string command = "ps -p " + pid;
   ProcessOptions options;
   ProcessResult result;
   error = core::system::runCommand(command, options, &result);
   if (error)
   {
      LOG_ERROR(error);
      return false;
   }

   // ps will return a non-zero exit status if no process with
   // the requested id is available -- if there is no process,
   // then this lockfile has been orphaned
   if (result.exitStatus != EXIT_SUCCESS)
      return true;

#endif /* _WIN32 */

   // assume the process is not orphaned if all previous checks failed
   return false;

}

} // end anonymous namespace

bool LinkBasedFileLock::isLockFileStale(const FilePath& lockFilePath)
{
   // check for orphaned lockfile
   if (isLockFileOrphaned(lockFilePath))
      return true;

   double seconds = s_timeoutInterval.total_seconds();
   double diff = ::difftime(::time(NULL), lockFilePath.lastWriteTime());
   return diff >= seconds;
}

namespace {

void cleanStaleLockfiles(const FilePath& dir)
{
   std::vector<FilePath> children;
   Error error = dir.children(&children);
   if (error)
      LOG_ERROR(error);

   BOOST_FOREACH(const FilePath& filePath, children)
   {
      if (boost::algorithm::starts_with(filePath.filename(), kFileLockPrefix) &&
          isLockFileStale(filePath))
      {
         Error error = filePath.removeIfExists();
         if (error)
            LOG_ERROR(error);
      }
   }
}

class LockRegistration : boost::noncopyable
{
public:

   void registerLock(const FilePath& lockFilePath)
   {
      LOCK_MUTEX(mutex_)
      {
         registration_.insert(lockFilePath);
      }
      END_LOCK_MUTEX
   }

   void deregisterLock(const FilePath& lockFilePath)
   {
      LOCK_MUTEX(mutex_)
      {
         registration_.erase(lockFilePath);
      }
      END_LOCK_MUTEX
   }

   void refreshLocks()
   {
      LOCK_MUTEX(mutex_)
      {
         BOOST_FOREACH(const FilePath& lockFilePath, registration_)
         {
            LOG("Bumping write time: " << lockFilePath.absolutePath());
            lockFilePath.setLastWriteTime();
         }
      }
      END_LOCK_MUTEX
   }

   void clearLocks()
   {
      LOCK_MUTEX(mutex_)
      {
         BOOST_FOREACH(const FilePath& lockFilePath, registration_)
         {
            Error error = lockFilePath.removeIfExists();
            if (error)
               LOG_ERROR(error);
            LOG("Clearing lock: " << lockFilePath.absolutePath());
         }
         registration_.clear();
      }
      END_LOCK_MUTEX
   }

private:

   boost::mutex mutex_;
   std::set<FilePath> registration_;
};

LockRegistration& lockRegistration()
{
   static LockRegistration instance;
   return instance;
}

Error writeLockFile(const FilePath& lockFilePath)
{

#ifndef _WIN32

   // generate proxy lockfile
   FilePath proxyPath = lockFilePath.parent().complete(proxyLockFileName());

   // since the proxy lockfile should be unique, it should _never_ be possible
   // for a collision to be found. if that does happen, it must be a leftover
   // from a previous process that crashed in this stage
   Error error = proxyPath.removeIfExists();
   if (error)
      LOG_ERROR(error);

   // ensure the proxy file is created, and remove it when we're done
   RemoveOnExitScope scope(proxyPath, ERROR_LOCATION);
   error = core::writeStringToFile(proxyPath, pidString());
   if (error)
   {
      // log the error since it isn't expected and could get swallowed
      // upstream by a caller ignore lock_not_available errors
      LOG_ERROR(error);
      return error;
   }

   // attempt to link to the desired location -- ignore return value
   // and just stat our original link after, as that's a more reliable
   // indicator of success on old NFS systems
   int status = ::link(
            proxyPath.absolutePathNative().c_str(),
            lockFilePath.absolutePathNative().c_str());

   // log errors (remove this if it is too noisy on NFS)
   if (status == -1)
   {
      int errorNumber = errno;

      // verbose logging
      LOG("ERROR: ::link() failed (errno " << errorNumber << ")" << std::endl <<
          "Attempted to link:" << std::endl << " - " <<
          "'" << proxyPath.absolutePathNative() << "'" <<
          " => " <<
          "'" << lockFilePath.absolutePathNative() << "'");

      LOG_ERROR(systemError(errorNumber, ERROR_LOCATION));
   }

   struct stat info;
   int errc = ::stat(proxyPath.absolutePathNative().c_str(), &info);
   if (errc)
   {
      int errorNumber = errno;

      // verbose logging
      LOG("ERROR: ::stat() failed (errno " << errorNumber << ")" << std::endl <<
          "Attempted to stat:" << std::endl << " - " <<
          "'" << proxyPath.absolutePathNative() << "'");

      // log the error since it isn't expected and could get swallowed
      // upstream by a caller ignoring lock_not_available errors
      Error error = systemError(errorNumber, ERROR_LOCATION);
      LOG_ERROR(error);
      return error;
   }

   // assume that a failure here is the result of someone else
   // acquiring the lock before we could
   if (info.st_nlink != 2)
   {
      LOG("WARNING: Failed to acquire lock (info.st_nlink == " << info.st_nlink << ")");
      return fileExistsError(ERROR_LOCATION);
   }

   return Success();

#else

   return systemError(boost::system::errc::function_not_supported, ERROR_LOCATION);

#endif
}

} // end anonymous namespace

struct LinkBasedFileLock::Impl
{
   FilePath lockFilePath;
};

LinkBasedFileLock::LinkBasedFileLock()
   : pImpl_(new Impl())
{
}

LinkBasedFileLock::~LinkBasedFileLock()
{
}

FilePath LinkBasedFileLock::lockFilePath() const
{
   return pImpl_->lockFilePath;
}

bool LinkBasedFileLock::isLocked(const FilePath& lockFilePath) const
{
   if (!lockFilePath.exists())
      return false;

   return !isLockFileStale(lockFilePath);
}

Error LinkBasedFileLock::acquire(const FilePath& lockFilePath)
{
   // if the lock file exists...
   if (lockFilePath.exists())
   {
      // ... and it's stale, it's a leftover lock from a previously
      // (crashed?) process. remove it and acquire our own lock
      if (isLockFileStale(lockFilePath))
      {
         // note that multiple processes may attempt to remove this
         // file at the same time, so errors shouldn't be fatal
         LOG("Removing stale lockfile: " << lockFilePath.absolutePath());
         Error error = lockFilePath.remove();
         if (error)
            LOG_ERROR(error);
      }

      // ... it's not stale -- someone else has the lock, cannot proceed
      else
      {
         LOG("No lock available: " << lockFilePath.absolutePath());
         return systemError(boost::system::errc::no_lock_available,
                            ERROR_LOCATION);
      }
   }

   // ensure the parent directory exists
   Error error = lockFilePath.parent().ensureDirectory();
   if (error)
      return error;

   // write the lock file -- this step _must_ be atomic and so only one
   // competing process should be able to succeed here
   error = writeLockFile(lockFilePath);
   if (error)
   {
      LOG("Failed to acquire lock: " << lockFilePath.absolutePath());
      return systemError(boost::system::errc::no_lock_available,
                         error,
                         ERROR_LOCATION);
   }

   // clean any other stale lockfiles in that directory
   cleanStaleLockfiles(lockFilePath.parent());

   // register our lock (for refresh)
   pImpl_->lockFilePath = lockFilePath;
   lockRegistration().registerLock(lockFilePath);
   LOG("Acquired lock: " << lockFilePath.absolutePath());
   return Success();
}

Error LinkBasedFileLock::release()
{
   const FilePath& lockFilePath = pImpl_->lockFilePath;
   LOG("Released lock: " << lockFilePath.absolutePath());

   Error error = lockFilePath.remove();
   if (error)
      LOG_ERROR(error);

   pImpl_->lockFilePath = FilePath();
   lockRegistration().deregisterLock(lockFilePath);
   return error;
}

void LinkBasedFileLock::refresh()
{
   lockRegistration().refreshLocks();
}

void LinkBasedFileLock::cleanUp()
{
   lockRegistration().clearLocks();
}

} // namespace core
} // namespace rstudio
<commit_msg>backup attempt for file locking<commit_after>/*
 * LinkBasedFileLock.cpp
 *
 * Copyright (C) 2009-12 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include <core/FileLock.hpp>

#include <errno.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>

#include <set>
#include <vector>

#include <core/SafeConvert.hpp>
#include <core/Algorithm.hpp>
#include <core/Thread.hpp>
#include <core/Error.hpp>
#include <core/Log.hpp>
#include <core/FilePath.hpp>
#include <core/FileSerializer.hpp>
#include <core/system/Process.hpp>
#include <core/system/System.hpp>

#include <boost/foreach.hpp>
#include <boost/system/error_code.hpp>

#define LOG(__X__)                                                             \
   do                                                                          \
   {                                                                           \
      if (::rstudio::core::FileLock::isLoggingEnabled())                       \
      {                                                                        \
         std::stringstream ss;                                                 \
         ss << "(PID " << ::getpid() << "): " << __X__ << std::endl;           \
         ::rstudio::core::FileLock::log(ss.str());                             \
      }                                                                        \
   } while (0)

namespace rstudio {
namespace core {

namespace {

const char * const kFileLockPrefix = ".rstudio-lock-41c29";

std::string pidString()
{
   PidType pid = system::currentProcessId();
   return safe_convert::numberToString((long) pid);
}

std::string hostName()
{
   char buffer[256];
   int status = ::gethostname(buffer, 255);
   if (status)
      LOG_ERROR(systemError(errno, ERROR_LOCATION));
   return std::string(buffer);
}

std::string threadId()
{
   std::stringstream ss;
   ss << boost::this_thread::get_id();
   return ss.str();
}

std::string proxyLockFileName()
{
   return std::string()
         + kFileLockPrefix
         + "-" + hostName()
         + "-" + pidString()
         + "-" + threadId();

}

bool isLockFileStale(const FilePath& lockFilePath)
{
   return LinkBasedFileLock::isLockFileStale(lockFilePath);
}

bool isLockFileOrphaned(const FilePath& lockFilePath)
{
#ifndef _WIN32

   Error error;

   // attempt to read pid from lockfile
   std::string pid;
   error = core::readStringFromFile(lockFilePath, &pid);
   if (error)
   {
      LOG_ERROR(error);
      return false;
   }
   pid = string_utils::trimWhitespace(pid);

#ifdef __linux__

   // on linux, we can check the proc filesystem for an associated
   // process -- if there is no such directory, then we assume that
   // this lockfile has been orphaned
   FilePath procPath("/proc/" + pid);
   if (!procPath.exists())
      return true;

#endif

   // call 'ps' to attempt to see if a process associated
   // with this process id exists (and get information about it)
   using namespace core::system;
   std::string command = "ps -p " + pid;
   ProcessOptions options;
   ProcessResult result;
   error = core::system::runCommand(command, options, &result);
   if (error)
   {
      LOG_ERROR(error);
      return false;
   }

   // ps will return a non-zero exit status if no process with
   // the requested id is available -- if there is no process,
   // then this lockfile has been orphaned
   if (result.exitStatus != EXIT_SUCCESS)
      return true;

#endif /* _WIN32 */

   // assume the process is not orphaned if all previous checks failed
   return false;

}

} // end anonymous namespace

bool LinkBasedFileLock::isLockFileStale(const FilePath& lockFilePath)
{
   // check for orphaned lockfile
   if (isLockFileOrphaned(lockFilePath))
      return true;

   double seconds = s_timeoutInterval.total_seconds();
   double diff = ::difftime(::time(NULL), lockFilePath.lastWriteTime());
   return diff >= seconds;
}

namespace {

void cleanStaleLockfiles(const FilePath& dir)
{
   std::vector<FilePath> children;
   Error error = dir.children(&children);
   if (error)
      LOG_ERROR(error);

   BOOST_FOREACH(const FilePath& filePath, children)
   {
      if (boost::algorithm::starts_with(filePath.filename(), kFileLockPrefix) &&
          isLockFileStale(filePath))
      {
         Error error = filePath.removeIfExists();
         if (error)
            LOG_ERROR(error);
      }
   }
}

class LockRegistration : boost::noncopyable
{
public:

   void registerLock(const FilePath& lockFilePath)
   {
      LOCK_MUTEX(mutex_)
      {
         registration_.insert(lockFilePath);
      }
      END_LOCK_MUTEX
   }

   void deregisterLock(const FilePath& lockFilePath)
   {
      LOCK_MUTEX(mutex_)
      {
         registration_.erase(lockFilePath);
      }
      END_LOCK_MUTEX
   }

   void refreshLocks()
   {
      LOCK_MUTEX(mutex_)
      {
         BOOST_FOREACH(const FilePath& lockFilePath, registration_)
         {
            LOG("Bumping write time: " << lockFilePath.absolutePath());
            lockFilePath.setLastWriteTime();
         }
      }
      END_LOCK_MUTEX
   }

   void clearLocks()
   {
      LOCK_MUTEX(mutex_)
      {
         BOOST_FOREACH(const FilePath& lockFilePath, registration_)
         {
            Error error = lockFilePath.removeIfExists();
            if (error)
               LOG_ERROR(error);
            LOG("Clearing lock: " << lockFilePath.absolutePath());
         }
         registration_.clear();
      }
      END_LOCK_MUTEX
   }

private:

   boost::mutex mutex_;
   std::set<FilePath> registration_;
};

LockRegistration& lockRegistration()
{
   static LockRegistration instance;
   return instance;
}

Error writeLockFile(const FilePath& lockFilePath)
{

#ifndef _WIN32

   // generate proxy lockfile
   FilePath proxyPath = lockFilePath.parent().complete(proxyLockFileName());

   // since the proxy lockfile should be unique, it should _never_ be possible
   // for a collision to be found. if that does happen, it must be a leftover
   // from a previous process that crashed in this stage
   Error error = proxyPath.removeIfExists();
   if (error)
      LOG_ERROR(error);

   // ensure the proxy file is created, and remove it when we're done
   std::string pid = pidString();
   RemoveOnExitScope scope(proxyPath, ERROR_LOCATION);
   error = core::writeStringToFile(proxyPath, pid);
   if (error)
   {
      // log the error since it isn't expected and could get swallowed
      // upstream by a caller ignore lock_not_available errors
      LOG_ERROR(error);
      return error;
   }

   // attempt to link to the desired location -- ignore return value
   // and just stat our original link after, as that's a more reliable
   // indicator of success on old NFS systems
   int status = ::link(
            proxyPath.absolutePathNative().c_str(),
            lockFilePath.absolutePathNative().c_str());

   // detect link failure
   if (status == -1)
   {
      // verbose logging
      int errorNumber = errno;
      LOG("ERROR: ::link() failed (errno " << errorNumber << ")" << std::endl <<
          "Attempted to link:" << std::endl << " - " <<
          "'" << proxyPath.absolutePathNative() << "'" <<
          " => " <<
          "'" << lockFilePath.absolutePathNative() << "'");

      // if this failed, we should still make a best-effort attempt to acquire
      // a lock by creating a file using O_CREAT | O_EXCL. note that we prefer
      // ::link() since older NFSes provide more guarantees as to its atomicity,
      // but not all NFS support ::link()
      int fd = ::open(
               lockFilePath.absolutePathNative().c_str(),
               O_WRONLY | O_CREAT | O_EXCL);

      if (fd == -1)
      {
         // verbose logging
         int errorNumber = errno;
         LOG("ERROR: ::open() failed (errno " << errorNumber << ")" <<
             std::endl << "Attempted to open:" << std::endl << " - " <<
             "'" << lockFilePath.absolutePathNative() << "'");

         return systemError(errorNumber, ERROR_LOCATION);
      }

      // acquired file descriptor -- now try writing our pid to the file
      // (save error number in case it fails and we need to report)
      int status = ::write(fd, pid.c_str(), pid.size());
      errorNumber = errno;

      // close file descriptor
      ::close(fd);

      // report if an error occurred during write
      if (status)
         return systemError(errorNumber, ERROR_LOCATION);

      return Success();
   }

   struct stat info;
   int errc = ::stat(proxyPath.absolutePathNative().c_str(), &info);
   if (errc)
   {
      int errorNumber = errno;

      // verbose logging
      LOG("ERROR: ::stat() failed (errno " << errorNumber << ")" << std::endl <<
          "Attempted to stat:" << std::endl << " - " <<
          "'" << proxyPath.absolutePathNative() << "'");

      // log the error since it isn't expected and could get swallowed
      // upstream by a caller ignoring lock_not_available errors
      Error error = systemError(errorNumber, ERROR_LOCATION);
      LOG_ERROR(error);
      return error;
   }

   // assume that a failure here is the result of someone else
   // acquiring the lock before we could
   if (info.st_nlink != 2)
   {
      LOG("WARNING: Failed to acquire lock (info.st_nlink == " << info.st_nlink << ")");
      return fileExistsError(ERROR_LOCATION);
   }

   return Success();

#else

   return systemError(boost::system::errc::function_not_supported, ERROR_LOCATION);

#endif
}

} // end anonymous namespace

struct LinkBasedFileLock::Impl
{
   FilePath lockFilePath;
};

LinkBasedFileLock::LinkBasedFileLock()
   : pImpl_(new Impl())
{
}

LinkBasedFileLock::~LinkBasedFileLock()
{
}

FilePath LinkBasedFileLock::lockFilePath() const
{
   return pImpl_->lockFilePath;
}

bool LinkBasedFileLock::isLocked(const FilePath& lockFilePath) const
{
   if (!lockFilePath.exists())
      return false;

   return !isLockFileStale(lockFilePath);
}

Error LinkBasedFileLock::acquire(const FilePath& lockFilePath)
{
   // if the lock file exists...
   if (lockFilePath.exists())
   {
      // ... and it's stale, it's a leftover lock from a previously
      // (crashed?) process. remove it and acquire our own lock
      if (isLockFileStale(lockFilePath))
      {
         // note that multiple processes may attempt to remove this
         // file at the same time, so errors shouldn't be fatal
         LOG("Removing stale lockfile: " << lockFilePath.absolutePath());
         Error error = lockFilePath.remove();
         if (error)
            LOG_ERROR(error);
      }

      // ... it's not stale -- someone else has the lock, cannot proceed
      else
      {
         LOG("No lock available: " << lockFilePath.absolutePath());
         return systemError(boost::system::errc::no_lock_available,
                            ERROR_LOCATION);
      }
   }

   // ensure the parent directory exists
   Error error = lockFilePath.parent().ensureDirectory();
   if (error)
      return error;

   // write the lock file -- this step _must_ be atomic and so only one
   // competing process should be able to succeed here
   error = writeLockFile(lockFilePath);
   if (error)
   {
      LOG("Failed to acquire lock: " << lockFilePath.absolutePath());
      return systemError(boost::system::errc::no_lock_available,
                         error,
                         ERROR_LOCATION);
   }

   // clean any other stale lockfiles in that directory
   cleanStaleLockfiles(lockFilePath.parent());

   // register our lock (for refresh)
   pImpl_->lockFilePath = lockFilePath;
   lockRegistration().registerLock(lockFilePath);
   LOG("Acquired lock: " << lockFilePath.absolutePath());
   return Success();
}

Error LinkBasedFileLock::release()
{
   const FilePath& lockFilePath = pImpl_->lockFilePath;
   LOG("Released lock: " << lockFilePath.absolutePath());

   Error error = lockFilePath.remove();
   if (error)
      LOG_ERROR(error);

   pImpl_->lockFilePath = FilePath();
   lockRegistration().deregisterLock(lockFilePath);
   return error;
}

void LinkBasedFileLock::refresh()
{
   lockRegistration().refreshLocks();
}

void LinkBasedFileLock::cleanUp()
{
   lockRegistration().clearLocks();
}

} // namespace core
} // namespace rstudio
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2018 Samsung Electronics Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

#include <dali-toolkit/dali-toolkit.h>
#include <dali/integration-api/debug.h>
#include <dali/devel-api/actors/actor-devel.h>
#include <dali-toolkit/devel-api/drag-drop-detector/drag-and-drop-detector.h>

using namespace Dali;
using Dali::Toolkit::TextLabel;
using namespace Dali::Toolkit;

namespace
{
Vector4 TEXT_LABEL_COLOR[] =
{
  Color::MAGENTA,
  Color::YELLOW,
  Color::CYAN,
  Color::BLUE,
  Color::MAGENTA,
  Color::YELLOW,
  Color::CYAN,
  Color::BLUE
};

const float TEXT_LABEL_POSITION_X = 100.0f;
const float TEXT_LABEL_POSITION_START_Y = 50.0f;
const float TEXT_LABEL_WIDTH = 250.0f;
const float TEXT_LABEL_HEIGHT = 70.0f;
const unsigned int TEXT_LABEL_NUM = sizeof(TEXT_LABEL_COLOR) / sizeof(TEXT_LABEL_COLOR[0]);

#if defined(DEBUG_ENABLED)
  Debug::Filter* gDragAndDropFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_DRAG_AND_DROP_EXAMPLE");
#endif
}

//This example shows how to use drag and drop function by several simple TextActors
class DragAndDropExample : public ConnectionTracker
{
public:

  DragAndDropExample( Application& application )
  : mApplication( application ),
    mDragIndex(-1),
    mDragRealIndex(-1),
    mDroppedFinished(false)
  {
    // Connect to the Application's Init signal
    mApplication.InitSignal().Connect( this, &DragAndDropExample::Create );
  }

  // The Init signal is received once (only) during the Application lifetime
  void Create( Application& application )
  {
    Stage stage = Stage::GetCurrent();
    stage.SetBackgroundColor( Color::WHITE );

    mDragAndDropDetector = Dali::Toolkit::DragAndDropDetector::New();

    // Respond to key events
    stage.KeyEventSignal().Connect( this, &DragAndDropExample::OnKeyEvent );

    TextLabel hintText = TextLabel::New("please drag one textlabel, move and drop on other textlabel");
    hintText.SetPosition(0.0f, 700.0f);
    hintText.SetParentOrigin(ParentOrigin::TOP_LEFT);
    hintText.SetAnchorPoint(AnchorPoint::TOP_LEFT);
    hintText.SetProperty(TextLabel::Property::MULTI_LINE, true);
    stage.Add(hintText);

    for(unsigned int i = 0 ; i < TEXT_LABEL_NUM; i++)
    {
      std::string str = "textlabel ";
      mTextLabel[i] = TextLabel::New(str + std::to_string(i));
      mTextLabel[i].SetParentOrigin(ParentOrigin::TOP_LEFT);
      mTextLabel[i].SetAnchorPoint(AnchorPoint::TOP_LEFT);
      mTextLabel[i].SetName("textlabel " + std::to_string(i));
      mTextLabel[i].SetLeaveRequired(true);
      mTextLabel[i].SetProperty(TextLabel::Property::HORIZONTAL_ALIGNMENT, "CENTER");
      mTextLabel[i].SetProperty(TextLabel::Property::VERTICAL_ALIGNMENT, "CENTER");
      mTextLabel[i].SetBackgroundColor(TEXT_LABEL_COLOR[i]);

      mTextLabel[i].SetSize(TEXT_LABEL_WIDTH, TEXT_LABEL_HEIGHT);
      mTextLabel[i].SetPosition(TEXT_LABEL_POSITION_X, TEXT_LABEL_POSITION_START_Y + TEXT_LABEL_HEIGHT * i);
      mDragAndDropDetector.Attach(mTextLabel[i]);

      mRect[i] = Rect<float>(TEXT_LABEL_POSITION_X, TEXT_LABEL_POSITION_START_Y + TEXT_LABEL_HEIGHT * i, TEXT_LABEL_WIDTH, TEXT_LABEL_HEIGHT);
      mOrder[i] = i;

      stage.Add(mTextLabel[i]);
    }

    mDragAndDropDetector.StartedSignal().Connect(this, &DragAndDropExample::OnStart);
    mDragAndDropDetector.EnteredSignal().Connect(this, &DragAndDropExample::OnEnter);
    mDragAndDropDetector.ExitedSignal().Connect(this, &DragAndDropExample::OnExit);
    mDragAndDropDetector.MovedSignal().Connect(this, &DragAndDropExample::OnMoved);
    mDragAndDropDetector.DroppedSignal().Connect(this, &DragAndDropExample::OnDropped);
    mDragAndDropDetector.EndedSignal().Connect(this, &DragAndDropExample::OnEnd);
  }

  void OnKeyEvent( const KeyEvent& event )
  {
    if( event.state == KeyEvent::Down )
    {
      if ( IsKey( event, Dali::DALI_KEY_ESCAPE ) || IsKey( event, Dali::DALI_KEY_BACK ) )
      {
        mApplication.Quit();
      }
    }
  }

  void OnStart(Control control, Dali::Toolkit::DragAndDropDetector detector)
  {
    DALI_LOG_INFO(gDragAndDropFilter, Debug::General, "---OnStart---\n");
    DALI_LOG_INFO(gDragAndDropFilter, Debug::General, "---control name is %s---\n", control.GetName().c_str());

    control.SetOpacity(0.1f);
    Vector2 screenPos  = detector.GetCurrentScreenPosition();
    control.ScreenToLocal(mDragLocalPos.x, mDragLocalPos.y,screenPos.x, screenPos.y );
    Rect<float> targetRect(screenPos.x, screenPos.y, 0.0f, 0.0f);

    for(unsigned int i = 0; i < TEXT_LABEL_NUM; i++)
    {
      if(mRect[i].Contains(targetRect))
      {
        mDragIndex = i;
      }
    }

    mDragRealIndex = mOrder[mDragIndex];
  }

  void OnEnter(Control control, Dali::Toolkit::DragAndDropDetector detector)
  {
    DALI_LOG_INFO(gDragAndDropFilter, Debug::General, "---OnEnter---\n");
    DALI_LOG_INFO(gDragAndDropFilter, Debug::General, "---control name is %s---\n", control.GetName().c_str());
  }

  void OnExit(Control control, Dali::Toolkit::DragAndDropDetector detector)
  {
    DALI_LOG_INFO(gDragAndDropFilter, Debug::General, "---OnExit---\n");
    DALI_LOG_INFO(gDragAndDropFilter, Debug::General, "---control name is %s---\n", control.GetName().c_str());
  }

  void OnMoved(Control control, Dali::Toolkit::DragAndDropDetector detector)
  {
    DALI_LOG_INFO(gDragAndDropFilter, Debug::Verbose, "---OnMoved---\n");
    DALI_LOG_INFO(gDragAndDropFilter, Debug::Verbose, "---control name is %s---\n", control.GetName().c_str());
    DALI_LOG_INFO(gDragAndDropFilter, Debug::Verbose, "---coordinate is (%f, %f)---\n", detector.GetCurrentScreenPosition().x, detector.GetCurrentScreenPosition().y);
  }

  void OnDropped(Control control, Dali::Toolkit::DragAndDropDetector detector)
  {
    DALI_LOG_INFO(gDragAndDropFilter, Debug::General, "---OnDropped---\n");
    DALI_LOG_INFO(gDragAndDropFilter, Debug::General, "---control name is %s---\n", control.GetName().c_str());

    Vector2 screenPos  = detector.GetCurrentScreenPosition();
    Rect<float> targetRect(screenPos.x, screenPos.y, 0.0f, 0.0f);
    int droppedIndex = -1;
    for(unsigned int i = 0; i < TEXT_LABEL_NUM; i++)
    {
      if(mRect[i].Contains(targetRect))
      {
        droppedIndex = i;
      }
    }

    Animation mAnimation = Animation::New(0.5f);

    if(droppedIndex > mDragIndex)
    {
      for(int i = mDragIndex + 1; i <= droppedIndex; i++)
      {
        float y = mTextLabel[mOrder[i]].GetCurrentPosition().y;
        mAnimation.AnimateTo(Property(mTextLabel[mOrder[i]], Actor::Property::POSITION), Vector3(TEXT_LABEL_POSITION_X, y - TEXT_LABEL_HEIGHT, 0.0f), AlphaFunction::EASE_OUT);
        mAnimation.Play();
      }

      int tmpId = mOrder[mDragIndex];
      for(int i = mDragIndex; i < droppedIndex; i++)
      {
        mOrder[i] = mOrder[i+1];
      }

      mOrder[droppedIndex] = tmpId;
    }
    else if(droppedIndex < mDragIndex)
    {

      for(int i = mDragIndex - 1; i >= droppedIndex; i--)
      {
        float y = mTextLabel[mOrder[i]].GetCurrentPosition().y;
        mAnimation.AnimateTo(Property(mTextLabel[mOrder[i]], Actor::Property::POSITION), Vector3(TEXT_LABEL_POSITION_X, y + TEXT_LABEL_HEIGHT, 0.0f), AlphaFunction::EASE_OUT);
        mAnimation.Play();
      }

      int tmpId = mOrder[mDragIndex];
      for(int i = mDragIndex; i > droppedIndex; i--)
      {
        mOrder[i] = mOrder[i-1];
      }

      mOrder[droppedIndex] = tmpId;

    }

    Vector2 pos = detector.GetCurrentScreenPosition();
    Vector2 localPos;
    control.GetParent().ScreenToLocal(localPos.x, localPos.y, pos.x, pos.y);

    KeyFrames k0 = KeyFrames::New();
    k0.Add(0.0f, Vector3(localPos.x - mDragLocalPos.x, localPos.y - mDragLocalPos.y, 0.0f));
    k0.Add(1.0f, Vector3(control.GetCurrentPosition().x, control.GetCurrentPosition().y, 0.0f));

    KeyFrames k1 = KeyFrames::New();
    k1.Add(0.0f, 0.1f);
    k1.Add(1.0f, 1.0f);

    Animation dropAnimation = Animation::New(0.5f);
    dropAnimation.FinishedSignal().Connect(this, &DragAndDropExample::DropAnimationFinished);
    dropAnimation.AnimateBetween(Property(mTextLabel[mDragRealIndex], Actor::Property::POSITION), k0, AlphaFunction::EASE_OUT);
    dropAnimation.AnimateBetween(Property(mTextLabel[mDragRealIndex], DevelActor::Property::OPACITY), k1, AlphaFunction::EASE_OUT);
    dropAnimation.Play();

    mDroppedFinished = true;
  }

  void DropAnimationFinished(Animation& animation)
  {
    for(unsigned int i = 0 ; i < TEXT_LABEL_NUM; i++)
    {
      mDragAndDropDetector.Attach(mTextLabel[i]);
    }
  }

  void OnEnd(Control control, Dali::Toolkit::DragAndDropDetector detector)
  {
    DALI_LOG_INFO(gDragAndDropFilter, Debug::General, "---OnEnd---\n");
    DALI_LOG_INFO(gDragAndDropFilter, Debug::General, "---control name is %s---\n", control.GetName().c_str());

    control.SetOpacity(1.0f);

    if(mDroppedFinished)
    {
      mDragAndDropDetector.DetachAll();
    }

    mDroppedFinished = false;
  }

private:
  Application&  mApplication;
  Dali::Toolkit::DragAndDropDetector mDragAndDropDetector;

  TextLabel mTextLabel[TEXT_LABEL_NUM];
  Rect<float> mRect[TEXT_LABEL_NUM];

  int mOrder[TEXT_LABEL_NUM];
  int mDragIndex;
  int mDragRealIndex;

  Vector2 mDragLocalPos;

  bool mDroppedFinished;

};

int DALI_EXPORT_API main( int argc, char **argv )
{
  Application application = Application::New( &argc, &argv );
  DragAndDropExample test( application );
  application.MainLoop();
  return 0;
}
<commit_msg>fix drag-and-drop example crash<commit_after>/*
 * Copyright (c) 2018 Samsung Electronics Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

#include <dali-toolkit/dali-toolkit.h>
#include <dali/integration-api/debug.h>
#include <dali/devel-api/actors/actor-devel.h>
#include <dali-toolkit/devel-api/drag-drop-detector/drag-and-drop-detector.h>

using namespace Dali;
using Dali::Toolkit::TextLabel;
using namespace Dali::Toolkit;

namespace
{
Vector4 TEXT_LABEL_COLOR[] =
{
  Color::MAGENTA,
  Color::YELLOW,
  Color::CYAN,
  Color::BLUE,
  Color::MAGENTA,
  Color::YELLOW,
  Color::CYAN,
  Color::BLUE
};

const float TEXT_LABEL_POSITION_X = 100.0f;
const float TEXT_LABEL_POSITION_START_Y = 50.0f;
const float TEXT_LABEL_WIDTH = 250.0f;
const float TEXT_LABEL_HEIGHT = 70.0f;
const unsigned int TEXT_LABEL_NUM = sizeof(TEXT_LABEL_COLOR) / sizeof(TEXT_LABEL_COLOR[0]);

#if defined(DEBUG_ENABLED)
  Debug::Filter* gDragAndDropFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_DRAG_AND_DROP_EXAMPLE");
#endif
}

//This example shows how to use drag and drop function by several simple TextActors
class DragAndDropExample : public ConnectionTracker
{
public:

  DragAndDropExample( Application& application )
  : mApplication( application ),
    mDragIndex(-1),
    mDragRealIndex(-1)
  {
    // Connect to the Application's Init signal
    mApplication.InitSignal().Connect( this, &DragAndDropExample::Create );
  }

  ~DragAndDropExample()
  {
    mDragAndDropDetector.DetachAll();
  }

  // The Init signal is received once (only) during the Application lifetime
  void Create( Application& application )
  {
    Stage stage = Stage::GetCurrent();
    stage.SetBackgroundColor( Color::WHITE );

    mDragAndDropDetector = Dali::Toolkit::DragAndDropDetector::New();

    // Respond to key events
    stage.KeyEventSignal().Connect( this, &DragAndDropExample::OnKeyEvent );

    TextLabel hintText = TextLabel::New("please drag one textlabel, move and drop on other textlabel");
    hintText.SetPosition(0.0f, 700.0f);
    hintText.SetParentOrigin(ParentOrigin::TOP_LEFT);
    hintText.SetAnchorPoint(AnchorPoint::TOP_LEFT);
    hintText.SetProperty(TextLabel::Property::MULTI_LINE, true);
    stage.Add(hintText);

    for(unsigned int i = 0 ; i < TEXT_LABEL_NUM; i++)
    {
      std::string str = "textlabel ";
      mTextLabel[i] = TextLabel::New(str + std::to_string(i));
      mTextLabel[i].SetParentOrigin(ParentOrigin::TOP_LEFT);
      mTextLabel[i].SetAnchorPoint(AnchorPoint::TOP_LEFT);
      mTextLabel[i].SetName("textlabel " + std::to_string(i));
      mTextLabel[i].SetLeaveRequired(true);
      mTextLabel[i].SetProperty(TextLabel::Property::HORIZONTAL_ALIGNMENT, "CENTER");
      mTextLabel[i].SetProperty(TextLabel::Property::VERTICAL_ALIGNMENT, "CENTER");
      mTextLabel[i].SetBackgroundColor(TEXT_LABEL_COLOR[i]);

      mTextLabel[i].SetSize(TEXT_LABEL_WIDTH, TEXT_LABEL_HEIGHT);
      mTextLabel[i].SetPosition(TEXT_LABEL_POSITION_X, TEXT_LABEL_POSITION_START_Y + TEXT_LABEL_HEIGHT * i);
      mDragAndDropDetector.Attach(mTextLabel[i]);

      mRect[i] = Rect<float>(TEXT_LABEL_POSITION_X, TEXT_LABEL_POSITION_START_Y + TEXT_LABEL_HEIGHT * i, TEXT_LABEL_WIDTH, TEXT_LABEL_HEIGHT);
      mOrder[i] = i;

      stage.Add(mTextLabel[i]);
    }

    mDragAndDropDetector.StartedSignal().Connect(this, &DragAndDropExample::OnStart);
    mDragAndDropDetector.EnteredSignal().Connect(this, &DragAndDropExample::OnEnter);
    mDragAndDropDetector.ExitedSignal().Connect(this, &DragAndDropExample::OnExit);
    mDragAndDropDetector.MovedSignal().Connect(this, &DragAndDropExample::OnMoved);
    mDragAndDropDetector.DroppedSignal().Connect(this, &DragAndDropExample::OnDropped);
    mDragAndDropDetector.EndedSignal().Connect(this, &DragAndDropExample::OnEnd);
  }

  void OnKeyEvent( const KeyEvent& event )
  {
    if( event.state == KeyEvent::Down )
    {
      if ( IsKey( event, Dali::DALI_KEY_ESCAPE ) || IsKey( event, Dali::DALI_KEY_BACK ) )
      {
        mApplication.Quit();
      }
    }
  }

  void OnStart(Control control, Dali::Toolkit::DragAndDropDetector detector)
  {
    DALI_LOG_INFO(gDragAndDropFilter, Debug::General, "---OnStart---\n");
    DALI_LOG_INFO(gDragAndDropFilter, Debug::General, "---control name is %s---\n", control.GetName().c_str());

    control.SetOpacity(0.1f);
    Vector2 screenPos  = detector.GetCurrentScreenPosition();
    control.ScreenToLocal(mDragLocalPos.x, mDragLocalPos.y,screenPos.x, screenPos.y );
    Rect<float> targetRect(screenPos.x, screenPos.y, 0.0f, 0.0f);

    for(unsigned int i = 0; i < TEXT_LABEL_NUM; i++)
    {
      if(mRect[i].Contains(targetRect))
      {
        mDragIndex = i;
      }
    }

    mDragRealIndex = mOrder[mDragIndex];
  }

  void OnEnter(Control control, Dali::Toolkit::DragAndDropDetector detector)
  {
    DALI_LOG_INFO(gDragAndDropFilter, Debug::General, "---OnEnter---\n");
    DALI_LOG_INFO(gDragAndDropFilter, Debug::General, "---control name is %s---\n", control.GetName().c_str());
  }

  void OnExit(Control control, Dali::Toolkit::DragAndDropDetector detector)
  {
    DALI_LOG_INFO(gDragAndDropFilter, Debug::General, "---OnExit---\n");
    DALI_LOG_INFO(gDragAndDropFilter, Debug::General, "---control name is %s---\n", control.GetName().c_str());
  }

  void OnMoved(Control control, Dali::Toolkit::DragAndDropDetector detector)
  {
    DALI_LOG_INFO(gDragAndDropFilter, Debug::Verbose, "---OnMoved---\n");
    DALI_LOG_INFO(gDragAndDropFilter, Debug::Verbose, "---control name is %s---\n", control.GetName().c_str());
    DALI_LOG_INFO(gDragAndDropFilter, Debug::Verbose, "---coordinate is (%f, %f)---\n", detector.GetCurrentScreenPosition().x, detector.GetCurrentScreenPosition().y);
  }

  void OnDropped(Control control, Dali::Toolkit::DragAndDropDetector detector)
  {
    DALI_LOG_INFO(gDragAndDropFilter, Debug::General, "---OnDropped---\n");
    DALI_LOG_INFO(gDragAndDropFilter, Debug::General, "---control name is %s---\n", control.GetName().c_str());

    Vector2 screenPos  = detector.GetCurrentScreenPosition();
    Rect<float> targetRect(screenPos.x, screenPos.y, 0.0f, 0.0f);
    int droppedIndex = -1;
    for(unsigned int i = 0; i < TEXT_LABEL_NUM; i++)
    {
      if(mRect[i].Contains(targetRect))
      {
        droppedIndex = i;
      }
    }

    Animation mAnimation = Animation::New(0.5f);

    if(droppedIndex > mDragIndex)
    {
      for(int i = mDragIndex + 1; i <= droppedIndex; i++)
      {
        float y = mTextLabel[mOrder[i]].GetCurrentPosition().y;
        mAnimation.AnimateTo(Property(mTextLabel[mOrder[i]], Actor::Property::POSITION), Vector3(TEXT_LABEL_POSITION_X, y - TEXT_LABEL_HEIGHT, 0.0f), AlphaFunction::EASE_OUT);
        mAnimation.Play();
      }

      int tmpId = mOrder[mDragIndex];
      for(int i = mDragIndex; i < droppedIndex; i++)
      {
        mOrder[i] = mOrder[i+1];
      }

      mOrder[droppedIndex] = tmpId;
    }
    else if(droppedIndex < mDragIndex)
    {

      for(int i = mDragIndex - 1; i >= droppedIndex; i--)
      {
        float y = mTextLabel[mOrder[i]].GetCurrentPosition().y;
        mAnimation.AnimateTo(Property(mTextLabel[mOrder[i]], Actor::Property::POSITION), Vector3(TEXT_LABEL_POSITION_X, y + TEXT_LABEL_HEIGHT, 0.0f), AlphaFunction::EASE_OUT);
        mAnimation.Play();
      }

      int tmpId = mOrder[mDragIndex];
      for(int i = mDragIndex; i > droppedIndex; i--)
      {
        mOrder[i] = mOrder[i-1];
      }

      mOrder[droppedIndex] = tmpId;

    }

    Vector2 pos = detector.GetCurrentScreenPosition();
    Vector2 localPos;
    control.GetParent().ScreenToLocal(localPos.x, localPos.y, pos.x, pos.y);

    KeyFrames k0 = KeyFrames::New();
    k0.Add(0.0f, Vector3(localPos.x - mDragLocalPos.x, localPos.y - mDragLocalPos.y, 0.0f));
    k0.Add(1.0f, Vector3(control.GetCurrentPosition().x, control.GetCurrentPosition().y, 0.0f));

    KeyFrames k1 = KeyFrames::New();
    k1.Add(0.0f, 0.1f);
    k1.Add(1.0f, 1.0f);

    Animation dropAnimation = Animation::New(0.5f);
    dropAnimation.AnimateBetween(Property(mTextLabel[mDragRealIndex], Actor::Property::POSITION), k0, AlphaFunction::EASE_OUT);
    dropAnimation.AnimateBetween(Property(mTextLabel[mDragRealIndex], DevelActor::Property::OPACITY), k1, AlphaFunction::EASE_OUT);
    dropAnimation.Play();
  }

  void DropAnimationFinished(Animation& animation)
  {
    for(unsigned int i = 0 ; i < TEXT_LABEL_NUM; i++)
    {
      mDragAndDropDetector.Attach(mTextLabel[i]);
    }
  }

  void OnEnd(Control control, Dali::Toolkit::DragAndDropDetector detector)
  {
    DALI_LOG_INFO(gDragAndDropFilter, Debug::General, "---OnEnd---\n");
    DALI_LOG_INFO(gDragAndDropFilter, Debug::General, "---control name is %s---\n", control.GetName().c_str());

    control.SetOpacity(1.0f);
  }

private:
  Application&  mApplication;
  Dali::Toolkit::DragAndDropDetector mDragAndDropDetector;

  TextLabel mTextLabel[TEXT_LABEL_NUM];
  Rect<float> mRect[TEXT_LABEL_NUM];

  int mOrder[TEXT_LABEL_NUM];
  int mDragIndex;
  int mDragRealIndex;

  Vector2 mDragLocalPos;

};

int DALI_EXPORT_API main( int argc, char **argv )
{
  Application application = Application::New( &argc, &argv );
  DragAndDropExample test( application );
  application.MainLoop();
  return 0;
}
<|endoftext|>


<commit_before>/* Copyright 2016 Stanford University, NVIDIA Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// This example demonstrates way in which virtual mapping can be useful -
// generating variable-sized output from a task

#include <legion.h>
#include <realm/cmdline.h>
#include <mappers/default_mapper.h>

using namespace Legion;
using namespace Legion::Mapping;
using namespace LegionRuntime::Accessor;

enum TaskID
{
  TOP_LEVEL_TASK_ID,
  MAKE_DATA_TASK_ID,
  USE_DATA_TASK_ID,
};

enum {
  FID_DATA = 55,
};

enum {
  PID_ALLOCED_DATA = 4,
};

LegionRuntime::Logger::Category log_app("app");

struct MakeDataTaskArgs {
  int random_seed;
  size_t average_output_size;
};

void top_level_task(const Task *task,
                    const std::vector<PhysicalRegion> &regions,
                    Context ctx, Runtime *runtime)
{
  size_t num_subregions = 4;
  size_t average_output_size = 100;
  size_t total_region_size = 1 << 30;
  int random_seed = 12345;

  const InputArgs &command_args = HighLevelRuntime::get_input_args();

  bool ok = Realm::CommandLineParser()
    .add_option_int("-n", num_subregions)
    .add_option_int("-s", average_output_size)
    .add_option_int("-l", total_region_size)
    .add_option_int("-seed", random_seed)
    .parse_command_line(command_args.argc, (const char **)command_args.argv);

  if(!ok) {
    log_app.fatal() << "error parsing command line arguments";
    exit(1);
  }

  // create a top-level region that is (easily) large enough to hold all of our
  // data - we need not worry about a tight bound, because we will never create
  // any instances of this size
  Rect<1> bounds(0, total_region_size - 1);
  IndexSpace is = runtime->create_index_space(ctx, Domain::from_rect<1>(bounds));
  runtime->attach_name(is, "is");

  // our field space will just have a single field
  FieldSpace fs = runtime->create_field_space(ctx);
  runtime->attach_name(fs, "fs");
  {
    FieldAllocator fsa = runtime->create_field_allocator(ctx, fs);
    fsa.allocate_field(sizeof(int), FID_DATA);
    runtime->attach_name(fs, FID_DATA, "data");
  }

  LogicalRegion lr = runtime->create_logical_region(ctx, is, fs);
  runtime->attach_name(lr, "lr");

  // partition it into equal pieces - again, these are expected to be much
  // larger than the actual output of the generator tasks
  Rect<1> subregion_idxs(0, num_subregions - 1);
  size_t elements_per_subregion = total_region_size / num_subregions;
  assert(elements_per_subregion >= (2 * average_output_size));
  Blockify<1> blockify(elements_per_subregion);
  IndexPartition ip = runtime->create_index_partition(ctx, is, blockify);
  LogicalPartition lp = runtime->get_logical_partition(ctx, lr, ip);

  // perform an index launch to have each subregion filled in with a variable
  // amount of data
  {
    MakeDataTaskArgs args;
    args.random_seed = random_seed;
    args.average_output_size = average_output_size;
    IndexLauncher launcher(MAKE_DATA_TASK_ID, Domain::from_rect<1>(subregion_idxs),
			   TaskArgument(&args, sizeof(args)),
			   ArgumentMap());
    launcher.add_region_requirement(RegionRequirement(lp,
						      0, // identity projection
						      READ_WRITE,
						      EXCLUSIVE,
						      lr,
						      DefaultMapper::VIRTUAL_MAP)
				    .add_field(FID_DATA));
    FutureMap fm = runtime->execute_index_space(ctx, launcher);
    fm.wait_all_results();
  }

  // now perform a second index launch to use the variable-sized chunks of
  // data
  {
    IndexLauncher launcher(USE_DATA_TASK_ID, Domain::from_rect<1>(subregion_idxs),
			   TaskArgument(0, 0),
			   ArgumentMap());
    launcher.add_region_requirement(RegionRequirement(lp,
						      0, // identity projection
						      READ_ONLY,
						      EXCLUSIVE,
						      lr,
						      DefaultMapper::VIRTUAL_MAP)
				    .add_field(FID_DATA));
    FutureMap fm = runtime->execute_index_space(ctx, launcher);
    fm.wait_all_results();
  }
}

void make_data_task(const Task *task,
                    const std::vector<PhysicalRegion> &regions,
                    Context ctx, Runtime *runtime)
{
  const MakeDataTaskArgs& args = *static_cast<const MakeDataTaskArgs *>(task->args);
  int subregion_index = task->index_point.get_point<1>();

  // we should _NOT_ have a mapping of our region
  //assert(!regions[0].is_mapped());

  // first, decide how much data we're going to produce
  unsigned short xsubi[3];
  xsubi[0] = args.random_seed >> 16;
  xsubi[1] = args.random_seed;
  xsubi[2] = subregion_index;
  coord_t output_size = nrand48(xsubi) % (2 * args.average_output_size + 1);

  log_app.print() << "make data: subregion " << subregion_index << ", output size = " << output_size;

  // now we can define a (sub-)subregion of our subregion that is the right size
  // to hold the output
  LogicalRegion my_lr = regions[0].get_logical_region();
  IndexSpace my_is = my_lr.get_index_space();
  Rect<1> my_bounds = runtime->get_index_space_domain(my_is).get_rect<1>();
  coord_t bounds_lo = my_bounds.lo[0];

  // remember rectangle bounds are inclusive on both sides
  Rect<1> alloc_bounds(my_bounds.lo, bounds_lo + output_size - 1);

  // create a new partition with a known part_color so that other tasks can find
  // the color space will consist of the single color '0'
  DomainColoring dc;
  Domain color_space = Domain::from_rect<1>(Rect<1>(0, 0));
  dc[0] = Domain::from_rect<1>(alloc_bounds);

  IndexPartition alloc_ip = runtime->create_index_partition(ctx,
							    my_is,
							    color_space,
							    dc,
							    DISJOINT_KIND, // trivial
							    PID_ALLOCED_DATA);

  // now we get the name of the logical subregion we just created and inline map
  // it to generate our output
  LogicalPartition alloc_lp = runtime->get_logical_partition(my_lr, alloc_ip);
  IndexSpace alloc_is = runtime->get_index_subspace(alloc_ip, DomainPoint::from_point<1>(0));
  LogicalRegion alloc_lr = runtime->get_logical_subregion(alloc_lp, alloc_is);

  log_app.debug() << "created subregion " << alloc_lr;

  // tell the default mapper that we want exactly this region to be mapped
  // otherwise, its heuristics may cause it to try to map the (huge) parent
  InlineLauncher launcher(RegionRequirement(alloc_lr,
					    READ_WRITE,
					    EXCLUSIVE,
					    my_lr,
					    DefaultMapper::EXACT_REGION)
			  .add_field(FID_DATA));
  PhysicalRegion pr = runtime->map_region(ctx, launcher);

  // this would be done as part of asking for an accessor, but do it explicitly for
  // didactic purposes - while inline mappings can often be expensive due to stalls or
  // data movement, this should be fast because we are just allocating new space
  pr.wait_until_valid();

  {
    RegionAccessor<AccessorType::Generic, int> ra = pr.get_field_accessor(FID_DATA).typeify<int>();

    for(coord_t i = 0; i < output_size; i++)
      ra.write(DomainPoint::from_point<1>(bounds_lo + i),
	       (subregion_index * 10000) + i);
  }

  // release our inline mapping
  runtime->unmap_region(ctx, pr);

  // no need to explicitly return the name of the subregion we created - it can be foud
  // by walking the region tree using known colors
}

void use_data_task(const Task *task,
		   const std::vector<PhysicalRegion> &regions,
		   Context ctx, Runtime *runtime)
{
  runtime->unmap_all_regions(ctx);
  int subregion_index = task->index_point.get_point<1>();

  PhysicalRegion pr = regions[0];
  Rect<1> my_bounds;
  bool was_virtual_mapped = true;
  if(was_virtual_mapped) {
    // find the actual subregion containing our input data by walking the
    // region tree
    LogicalRegion my_lr = regions[0].get_logical_region();
    IndexSpace my_is = my_lr.get_index_space();

    IndexPartition alloc_ip = runtime->get_index_partition(my_is, PID_ALLOCED_DATA);

    // getting from the index partition to the logical subregion is identical to
    // what was done in make_data_task()
    LogicalPartition alloc_lp = runtime->get_logical_partition(my_lr, alloc_ip);
    IndexSpace alloc_is = runtime->get_index_subspace(alloc_ip, DomainPoint::from_point<1>(0));
    LogicalRegion alloc_lr = runtime->get_logical_subregion(alloc_lp, alloc_is);

    log_app.debug() << "looked up subregion " << alloc_lr;

    // learn the input size from the bounds of the allocated subspace
    my_bounds = runtime->get_index_space_domain(alloc_is).get_rect<1>();

    // again, tell the default mapper that we want exactly this region to be mapped
    // this is important if the mapper sends us to a different place than where the
    // data was produced and a copy is needed
    InlineLauncher launcher(RegionRequirement(alloc_lr,
					      READ_ONLY,
					      EXCLUSIVE,
					      my_lr,
					      DefaultMapper::EXACT_REGION)
			    .add_field(FID_DATA));
    PhysicalRegion pr = runtime->map_region(ctx, launcher);
  }

  coord_t bounds_lo = my_bounds.lo[0];
  coord_t input_size = my_bounds.volume();

  log_app.print() << "use data: subregion " << subregion_index << ", input size = " << input_size;

  // check that the data is what we expect
  int errors = 0;
  {
    RegionAccessor<AccessorType::Generic, int> ra = pr.get_field_accessor(FID_DATA).typeify<int>();

    for(coord_t i = 0; i < input_size; i++) {
      int exp = (subregion_index * 10000) + i;
      int act = ra.read(DomainPoint::from_point<1>(bounds_lo + i));
      if(exp != act) {
	log_app.error() << "mismatch in subregion " << subregion_index << ": ["
			<< (bounds_lo + i) << "] = " << act << " (expected " << exp << ")";
	errors++;
      }
    }
  }

  // unmap any inline mapping we did
  if(was_virtual_mapped)
    runtime->unmap_region(ctx, pr);

  //return errors;
}

int main(int argc, char **argv)
{
  // Register our task variants
  {
    TaskVariantRegistrar top_level_registrar(TOP_LEVEL_TASK_ID);
    top_level_registrar.add_constraint(ProcessorConstraint(Processor::LOC_PROC));
    Runtime::preregister_task_variant<top_level_task>(top_level_registrar,
                                                      "Top Level Task");
    Runtime::set_top_level_task_id(TOP_LEVEL_TASK_ID);
  }
  {
    TaskVariantRegistrar make_data_registrar(MAKE_DATA_TASK_ID);
    make_data_registrar.add_constraint(ProcessorConstraint(Processor::LOC_PROC));
    Runtime::preregister_task_variant<make_data_task>(make_data_registrar,
                                                      "Make Data Task");
  }
  {
    TaskVariantRegistrar use_data_registrar(USE_DATA_TASK_ID);
    use_data_registrar.add_constraint(ProcessorConstraint(Processor::LOC_PROC));
    Runtime::preregister_task_variant<use_data_task>(use_data_registrar,
						     "Use Data Task");
  }

  // Fire up the runtime
  return Runtime::start(argc, argv);
}
<commit_msg>examples: fixing a bug in the virtual mapping example<commit_after>/* Copyright 2016 Stanford University, NVIDIA Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// This example demonstrates way in which virtual mapping can be useful -
// generating variable-sized output from a task

#include <legion.h>
#include <realm/cmdline.h>
#include <mappers/default_mapper.h>

using namespace Legion;
using namespace Legion::Mapping;
using namespace LegionRuntime::Accessor;

enum TaskID
{
  TOP_LEVEL_TASK_ID,
  MAKE_DATA_TASK_ID,
  USE_DATA_TASK_ID,
};

enum {
  FID_DATA = 55,
};

enum {
  PID_ALLOCED_DATA = 4,
};

LegionRuntime::Logger::Category log_app("app");

struct MakeDataTaskArgs {
  int random_seed;
  size_t average_output_size;
};

void top_level_task(const Task *task,
                    const std::vector<PhysicalRegion> &regions,
                    Context ctx, Runtime *runtime)
{
  size_t num_subregions = 4;
  size_t average_output_size = 100;
  size_t total_region_size = 1 << 30;
  int random_seed = 12345;

  const InputArgs &command_args = HighLevelRuntime::get_input_args();

  bool ok = Realm::CommandLineParser()
    .add_option_int("-n", num_subregions)
    .add_option_int("-s", average_output_size)
    .add_option_int("-l", total_region_size)
    .add_option_int("-seed", random_seed)
    .parse_command_line(command_args.argc, (const char **)command_args.argv);

  if(!ok) {
    log_app.fatal() << "error parsing command line arguments";
    exit(1);
  }

  // create a top-level region that is (easily) large enough to hold all of our
  // data - we need not worry about a tight bound, because we will never create
  // any instances of this size
  Rect<1> bounds(0, total_region_size - 1);
  IndexSpace is = runtime->create_index_space(ctx, Domain::from_rect<1>(bounds));
  runtime->attach_name(is, "is");

  // our field space will just have a single field
  FieldSpace fs = runtime->create_field_space(ctx);
  runtime->attach_name(fs, "fs");
  {
    FieldAllocator fsa = runtime->create_field_allocator(ctx, fs);
    fsa.allocate_field(sizeof(int), FID_DATA);
    runtime->attach_name(fs, FID_DATA, "data");
  }

  LogicalRegion lr = runtime->create_logical_region(ctx, is, fs);
  runtime->attach_name(lr, "lr");

  // partition it into equal pieces - again, these are expected to be much
  // larger than the actual output of the generator tasks
  Rect<1> subregion_idxs(0, num_subregions - 1);
  size_t elements_per_subregion = total_region_size / num_subregions;
  assert(elements_per_subregion >= (2 * average_output_size));
  Blockify<1> blockify(elements_per_subregion);
  IndexPartition ip = runtime->create_index_partition(ctx, is, blockify);
  LogicalPartition lp = runtime->get_logical_partition(ctx, lr, ip);

  // perform an index launch to have each subregion filled in with a variable
  // amount of data
  {
    MakeDataTaskArgs args;
    args.random_seed = random_seed;
    args.average_output_size = average_output_size;
    IndexLauncher launcher(MAKE_DATA_TASK_ID, Domain::from_rect<1>(subregion_idxs),
			   TaskArgument(&args, sizeof(args)),
			   ArgumentMap());
    launcher.add_region_requirement(RegionRequirement(lp,
						      0, // identity projection
						      READ_WRITE,
						      EXCLUSIVE,
						      lr,
						      DefaultMapper::VIRTUAL_MAP)
				    .add_field(FID_DATA));
    FutureMap fm = runtime->execute_index_space(ctx, launcher);
    fm.wait_all_results();
  }

  // now perform a second index launch to use the variable-sized chunks of
  // data
  {
    IndexLauncher launcher(USE_DATA_TASK_ID, Domain::from_rect<1>(subregion_idxs),
			   TaskArgument(0, 0),
			   ArgumentMap());
    launcher.add_region_requirement(RegionRequirement(lp,
						      0, // identity projection
						      READ_ONLY,
						      EXCLUSIVE,
						      lr,
						      DefaultMapper::VIRTUAL_MAP)
				    .add_field(FID_DATA));
    FutureMap fm = runtime->execute_index_space(ctx, launcher);
    fm.wait_all_results();
  }
}

void make_data_task(const Task *task,
                    const std::vector<PhysicalRegion> &regions,
                    Context ctx, Runtime *runtime)
{
  const MakeDataTaskArgs& args = *static_cast<const MakeDataTaskArgs *>(task->args);
  int subregion_index = task->index_point.get_point<1>();

  // we should _NOT_ have a mapping of our region
  //assert(!regions[0].is_mapped());

  // first, decide how much data we're going to produce
  unsigned short xsubi[3];
  xsubi[0] = args.random_seed >> 16;
  xsubi[1] = args.random_seed;
  xsubi[2] = subregion_index;
  coord_t output_size = nrand48(xsubi) % (2 * args.average_output_size + 1);

  log_app.print() << "make data: subregion " << subregion_index << ", output size = " << output_size;

  // now we can define a (sub-)subregion of our subregion that is the right size
  // to hold the output
  LogicalRegion my_lr = regions[0].get_logical_region();
  IndexSpace my_is = my_lr.get_index_space();
  Rect<1> my_bounds = runtime->get_index_space_domain(my_is).get_rect<1>();
  coord_t bounds_lo = my_bounds.lo[0];

  // remember rectangle bounds are inclusive on both sides
  Rect<1> alloc_bounds(my_bounds.lo, bounds_lo + output_size - 1);

  // create a new partition with a known part_color so that other tasks can find
  // the color space will consist of the single color '0'
  DomainColoring dc;
  Domain color_space = Domain::from_rect<1>(Rect<1>(0, 0));
  dc[0] = Domain::from_rect<1>(alloc_bounds);

  IndexPartition alloc_ip = runtime->create_index_partition(ctx,
							    my_is,
							    color_space,
							    dc,
							    DISJOINT_KIND, // trivial
							    PID_ALLOCED_DATA);

  // now we get the name of the logical subregion we just created and inline map
  // it to generate our output
  LogicalPartition alloc_lp = runtime->get_logical_partition(my_lr, alloc_ip);
  IndexSpace alloc_is = runtime->get_index_subspace(alloc_ip, DomainPoint::from_point<1>(0));
  LogicalRegion alloc_lr = runtime->get_logical_subregion(alloc_lp, alloc_is);

  log_app.debug() << "created subregion " << alloc_lr;

  // tell the default mapper that we want exactly this region to be mapped
  // otherwise, its heuristics may cause it to try to map the (huge) parent
  InlineLauncher launcher(RegionRequirement(alloc_lr,
					    READ_WRITE,
					    EXCLUSIVE,
					    my_lr,
					    DefaultMapper::EXACT_REGION)
			  .add_field(FID_DATA));
  PhysicalRegion pr = runtime->map_region(ctx, launcher);

  // this would be done as part of asking for an accessor, but do it explicitly for
  // didactic purposes - while inline mappings can often be expensive due to stalls or
  // data movement, this should be fast because we are just allocating new space
  pr.wait_until_valid();

  {
    RegionAccessor<AccessorType::Generic, int> ra = pr.get_field_accessor(FID_DATA).typeify<int>();

    for(coord_t i = 0; i < output_size; i++)
      ra.write(DomainPoint::from_point<1>(bounds_lo + i),
	       (subregion_index * 10000) + i);
  }

  // release our inline mapping
  runtime->unmap_region(ctx, pr);

  // no need to explicitly return the name of the subregion we created - it can be foud
  // by walking the region tree using known colors
}

void use_data_task(const Task *task,
		   const std::vector<PhysicalRegion> &regions,
		   Context ctx, Runtime *runtime)
{
  runtime->unmap_all_regions(ctx);
  int subregion_index = task->index_point.get_point<1>();

  PhysicalRegion pr = regions[0];
  Rect<1> my_bounds;
  bool was_virtual_mapped = true;
  if(was_virtual_mapped) {
    // find the actual subregion containing our input data by walking the
    // region tree
    LogicalRegion my_lr = regions[0].get_logical_region();
    IndexSpace my_is = my_lr.get_index_space();

    IndexPartition alloc_ip = runtime->get_index_partition(my_is, PID_ALLOCED_DATA);

    // getting from the index partition to the logical subregion is identical to
    // what was done in make_data_task()
    LogicalPartition alloc_lp = runtime->get_logical_partition(my_lr, alloc_ip);
    IndexSpace alloc_is = runtime->get_index_subspace(alloc_ip, DomainPoint::from_point<1>(0));
    LogicalRegion alloc_lr = runtime->get_logical_subregion(alloc_lp, alloc_is);

    log_app.debug() << "looked up subregion " << alloc_lr;

    // learn the input size from the bounds of the allocated subspace
    my_bounds = runtime->get_index_space_domain(alloc_is).get_rect<1>();

    // again, tell the default mapper that we want exactly this region to be mapped
    // this is important if the mapper sends us to a different place than where the
    // data was produced and a copy is needed
    InlineLauncher launcher(RegionRequirement(alloc_lr,
					      READ_ONLY,
					      EXCLUSIVE,
					      my_lr,
					      DefaultMapper::EXACT_REGION)
			    .add_field(FID_DATA));
    pr = runtime->map_region(ctx, launcher);
  }

  coord_t bounds_lo = my_bounds.lo[0];
  coord_t input_size = my_bounds.volume();

  log_app.print() << "use data: subregion " << subregion_index << ", input size = " << input_size;

  // check that the data is what we expect
  int errors = 0;
  {
    RegionAccessor<AccessorType::Generic, int> ra = pr.get_field_accessor(FID_DATA).typeify<int>();

    for(coord_t i = 0; i < input_size; i++) {
      int exp = (subregion_index * 10000) + i;
      int act = ra.read(DomainPoint::from_point<1>(bounds_lo + i));
      if(exp != act) {
	log_app.error() << "mismatch in subregion " << subregion_index << ": ["
			<< (bounds_lo + i) << "] = " << act << " (expected " << exp << ")";
	errors++;
      }
    }
  }

  // unmap any inline mapping we did
  if(was_virtual_mapped)
    runtime->unmap_region(ctx, pr);

  //return errors;
}

int main(int argc, char **argv)
{
  // Register our task variants
  {
    TaskVariantRegistrar top_level_registrar(TOP_LEVEL_TASK_ID);
    top_level_registrar.add_constraint(ProcessorConstraint(Processor::LOC_PROC));
    Runtime::preregister_task_variant<top_level_task>(top_level_registrar,
                                                      "Top Level Task");
    Runtime::set_top_level_task_id(TOP_LEVEL_TASK_ID);
  }
  {
    TaskVariantRegistrar make_data_registrar(MAKE_DATA_TASK_ID);
    make_data_registrar.add_constraint(ProcessorConstraint(Processor::LOC_PROC));
    Runtime::preregister_task_variant<make_data_task>(make_data_registrar,
                                                      "Make Data Task");
  }
  {
    TaskVariantRegistrar use_data_registrar(USE_DATA_TASK_ID);
    use_data_registrar.add_constraint(ProcessorConstraint(Processor::LOC_PROC));
    Runtime::preregister_task_variant<use_data_task>(use_data_registrar,
						     "Use Data Task");
  }

  // Fire up the runtime
  return Runtime::start(argc, argv);
}
<|endoftext|>


<commit_before>#include "coverage.h"
#include "featurecoverage.h"
#include "feature.h"
#include "featureiterator.h"
#include "drawingcolor.h"
#include "drawerfactory.h"
#include "rootdrawer.h"
#include "table.h"
#include "range.h"
#include "itemrange.h"
#include "colorrange.h"
#include "colorlookup.h"
#include "representation.h"
#include "attributevisualproperties.h"
#include "featurelayerdrawer.h"
#include "tesselation/ilwistesselator.h"
#include "openglhelper.h"

using namespace Ilwis;
using namespace Geodrawer;

REGISTER_DRAWER(FeatureLayerDrawer)

FeatureLayerDrawer::FeatureLayerDrawer(DrawerInterface *parentDrawer, RootDrawer *rootdrawer) : LayerDrawer("FeatureLayerDrawer", parentDrawer, rootdrawer)
{
}

DrawerInterface *FeatureLayerDrawer::create(DrawerInterface *parentDrawer, RootDrawer *rootdrawer)
{
    return new FeatureLayerDrawer(parentDrawer, rootdrawer)    ;
}

bool FeatureLayerDrawer::prepare(DrawerInterface::PreparationType prepType, const IOOptions &options, QOpenGLContext *openglContext)
{
    if(!LayerDrawer::prepare(prepType, options, openglContext))
        return false;

    if ( hasType(prepType, DrawerInterface::ptGEOMETRY)){
        std::vector<VertexPosition> vertices;
        std::vector<VertexColor> colors;

        _indices = std::vector<VertexIndex>();

        IFeatureCoverage features = coverage().as<FeatureCoverage>();
        if ( !features.isValid()){
            return ERROR2(ERR_COULDNT_CREATE_OBJECT_FOR_2,"FeatureCoverage", TR("Visualization"));
        }
        AttributeVisualProperties attr = attribute(activeAttribute());
        int columnIndex = features->attributeDefinitions().columnIndex(activeAttribute());
        for(const SPFeatureI& feature : features){
            quint32 noOfVertices = OpenGLHelper::getVertices(rootDrawer()->coordinateSystem(), features->coordinateSystem(), feature->geometry(), feature->featureid(), vertices, _indices, _boundaryIndex);
            for(int i =0; i < noOfVertices; ++i){
               QColor clr = attr.value2color(feature(activeAttribute()));
            //   if ( i % 2 == 0)
                colors.push_back(VertexColor(clr.redF(), clr.greenF(), clr.blueF(), 1.0));
            //   else
               // colors.push_back(VertexColor(1,0.5,0.75,1));
            }

        }

        if(!initGeometry(openglContext, vertices, colors))
            return false;

        _prepared |= DrawerInterface::ptGEOMETRY;

    }

    return true;
}

void FeatureLayerDrawer::setActiveAttribute(const QString &attr)
{
    IFeatureCoverage features = coverage().as<FeatureCoverage>();
    if ( features.isValid())    {
        if ( features->attributeDefinitions().columnIndex(attr) != iUNDEF){

            IRepresentation newrpr = Representation::defaultRepresentation(features->attributeDefinitions().columndefinition(attr).datadef().domain());
            if ( newrpr.isValid()){
                LayerDrawer::setActiveAttribute(attr);
            }
        }
    }
}

void FeatureLayerDrawer::coverage(const ICoverage &cov)
{
    LayerDrawer::coverage(cov);
    setActiveAttribute(sUNDEF);
    IFeatureCoverage features = coverage().as<FeatureCoverage>();

    for(int i = 0; i < features->attributeDefinitions().definitionCount(); ++i){
        IlwisTypes attrType = features->attributeDefinitions().columndefinition(i).datadef().domain()->ilwisType();
        if ( hasType(attrType, itNUMERICDOMAIN | itITEMDOMAIN)){
            AttributeVisualProperties props(features->attributeDefinitions().columndefinition(i).datadef().domain());
            if ( attrType == itNUMERICDOMAIN){
                SPNumericRange numrange = features->attributeDefinitions().columndefinition(i).datadef().range<NumericRange>();
                props.actualRange(NumericRange(numrange->min(), numrange->max(), numrange->resolution()));
            }
            attribute(features->attributeDefinitions().columndefinition(i).name(), props);
            // try to find a reasonable default for the activeattribute
            if ( activeAttribute() == sUNDEF){
                if ( features->attributeDefinitions().columnIndex(FEATUREVALUECOLUMN) != iUNDEF){
                    setActiveAttribute(FEATUREVALUECOLUMN);
                }else if ( features->attributeDefinitions().columnIndex(COVERAGEKEYCOLUMN) != iUNDEF){
                    setActiveAttribute(COVERAGEKEYCOLUMN);
                }
                else if ( hasType(features->attributeDefinitions().columndefinition(i).datadef().domain()->ilwisType(), itNUMERICDOMAIN)){
                    setActiveAttribute(features->attributeDefinitions().columndefinition(i).name());
                }
            }
        }
    }
}

ICoverage FeatureLayerDrawer::coverage() const
{
    return SpatialDataDrawer::coverage();
}

bool FeatureLayerDrawer::draw(QOpenGLContext *openglContext, const IOOptions& options) {
    if ( !openglContext){
        return ERROR2(QString("%1 : %2"),TR("Drawing failed"),TR("Invalid OpenGL context passed"));
    }

    if ( !isActive())
        return false;

    if (!isPrepared(DrawerInterface::ptGEOMETRY)){
        if (!prepare(DrawerInterface::ptGEOMETRY, options, openglContext)){
            return false;
        }
    }
    _shaders.bind();

    openglContext->functions()->glBindBuffer(GL_ARRAY_BUFFER,_vboPosition);

    int vertexLocation = _shaders.attributeLocation("position");
    openglContext->functions()->glVertexAttribPointer(vertexLocation,3,GL_FLOAT,FALSE,0,0);
    openglContext->functions()->glEnableVertexAttribArray(vertexLocation);

    openglContext->functions()->glBindBuffer(GL_ARRAY_BUFFER,_vboColor);

    int colorLocation = _shaders.attributeLocation("vertexColor");
    openglContext->functions()->glVertexAttribPointer(colorLocation,4,GL_FLOAT,FALSE,0, 0);
    openglContext->functions()->glEnableVertexAttribArray(colorLocation);

    for(int i =0; i < _indices.size(); ++i){
        if ( _indices[i]._geomtype == itLINE){
            glDrawArrays(GL_LINE_STRIP,_indices[i]._start,_indices[i]._count);
        } else if ( _indices[i]._geomtype == itPOLYGON ){
            glDrawArrays(GL_TRIANGLE_FAN,_indices[i]._start,_indices[i]._count);
        }
    }

    openglContext->functions()->glBindBuffer(GL_ARRAY_BUFFER, 0);
    openglContext->functions()->glDisableVertexAttribArray(colorLocation);
    openglContext->functions()->glDisableVertexAttribArray(vertexLocation);

    _shaders.release();

    return true;
}
<commit_msg>removed some comments<commit_after>#include "coverage.h"
#include "featurecoverage.h"
#include "feature.h"
#include "featureiterator.h"
#include "drawingcolor.h"
#include "drawerfactory.h"
#include "rootdrawer.h"
#include "table.h"
#include "range.h"
#include "itemrange.h"
#include "colorrange.h"
#include "colorlookup.h"
#include "representation.h"
#include "attributevisualproperties.h"
#include "featurelayerdrawer.h"
#include "tesselation/ilwistesselator.h"
#include "openglhelper.h"

using namespace Ilwis;
using namespace Geodrawer;

REGISTER_DRAWER(FeatureLayerDrawer)

FeatureLayerDrawer::FeatureLayerDrawer(DrawerInterface *parentDrawer, RootDrawer *rootdrawer) : LayerDrawer("FeatureLayerDrawer", parentDrawer, rootdrawer)
{
}

DrawerInterface *FeatureLayerDrawer::create(DrawerInterface *parentDrawer, RootDrawer *rootdrawer)
{
    return new FeatureLayerDrawer(parentDrawer, rootdrawer)    ;
}

bool FeatureLayerDrawer::prepare(DrawerInterface::PreparationType prepType, const IOOptions &options, QOpenGLContext *openglContext)
{
    if(!LayerDrawer::prepare(prepType, options, openglContext))
        return false;

    if ( hasType(prepType, DrawerInterface::ptGEOMETRY)){
        std::vector<VertexPosition> vertices;
        std::vector<VertexColor> colors;

        _indices = std::vector<VertexIndex>();

        IFeatureCoverage features = coverage().as<FeatureCoverage>();
        if ( !features.isValid()){
            return ERROR2(ERR_COULDNT_CREATE_OBJECT_FOR_2,"FeatureCoverage", TR("Visualization"));
        }
        AttributeVisualProperties attr = attribute(activeAttribute());
        int columnIndex = features->attributeDefinitions().columnIndex(activeAttribute());
        for(const SPFeatureI& feature : features){
            quint32 noOfVertices = OpenGLHelper::getVertices(rootDrawer()->coordinateSystem(), features->coordinateSystem(), feature->geometry(), feature->featureid(), vertices, _indices, _boundaryIndex);
            for(int i =0; i < noOfVertices; ++i){
               QColor clr = attr.value2color(feature(activeAttribute()));
               colors.push_back(VertexColor(clr.redF(), clr.greenF(), clr.blueF(), 1.0));
            }

        }

        if(!initGeometry(openglContext, vertices, colors))
            return false;

        _prepared |= DrawerInterface::ptGEOMETRY;

    }

    return true;
}

void FeatureLayerDrawer::setActiveAttribute(const QString &attr)
{
    IFeatureCoverage features = coverage().as<FeatureCoverage>();
    if ( features.isValid())    {
        if ( features->attributeDefinitions().columnIndex(attr) != iUNDEF){

            IRepresentation newrpr = Representation::defaultRepresentation(features->attributeDefinitions().columndefinition(attr).datadef().domain());
            if ( newrpr.isValid()){
                LayerDrawer::setActiveAttribute(attr);
            }
        }
    }
}

void FeatureLayerDrawer::coverage(const ICoverage &cov)
{
    LayerDrawer::coverage(cov);
    setActiveAttribute(sUNDEF);
    IFeatureCoverage features = coverage().as<FeatureCoverage>();

    for(int i = 0; i < features->attributeDefinitions().definitionCount(); ++i){
        IlwisTypes attrType = features->attributeDefinitions().columndefinition(i).datadef().domain()->ilwisType();
        if ( hasType(attrType, itNUMERICDOMAIN | itITEMDOMAIN)){
            AttributeVisualProperties props(features->attributeDefinitions().columndefinition(i).datadef().domain());
            if ( attrType == itNUMERICDOMAIN){
                SPNumericRange numrange = features->attributeDefinitions().columndefinition(i).datadef().range<NumericRange>();
                props.actualRange(NumericRange(numrange->min(), numrange->max(), numrange->resolution()));
            }
            attribute(features->attributeDefinitions().columndefinition(i).name(), props);
            // try to find a reasonable default for the activeattribute
            if ( activeAttribute() == sUNDEF){
                if ( features->attributeDefinitions().columnIndex(FEATUREVALUECOLUMN) != iUNDEF){
                    setActiveAttribute(FEATUREVALUECOLUMN);
                }else if ( features->attributeDefinitions().columnIndex(COVERAGEKEYCOLUMN) != iUNDEF){
                    setActiveAttribute(COVERAGEKEYCOLUMN);
                }
                else if ( hasType(features->attributeDefinitions().columndefinition(i).datadef().domain()->ilwisType(), itNUMERICDOMAIN)){
                    setActiveAttribute(features->attributeDefinitions().columndefinition(i).name());
                }
            }
        }
    }
}

ICoverage FeatureLayerDrawer::coverage() const
{
    return SpatialDataDrawer::coverage();
}

bool FeatureLayerDrawer::draw(QOpenGLContext *openglContext, const IOOptions& options) {
    if ( !openglContext){
        return ERROR2(QString("%1 : %2"),TR("Drawing failed"),TR("Invalid OpenGL context passed"));
    }

    if ( !isActive())
        return false;

    if (!isPrepared(DrawerInterface::ptGEOMETRY)){
        if (!prepare(DrawerInterface::ptGEOMETRY, options, openglContext)){
            return false;
        }
    }
    _shaders.bind();

    openglContext->functions()->glBindBuffer(GL_ARRAY_BUFFER,_vboPosition);

    int vertexLocation = _shaders.attributeLocation("position");
    openglContext->functions()->glVertexAttribPointer(vertexLocation,3,GL_FLOAT,FALSE,0,0);
    openglContext->functions()->glEnableVertexAttribArray(vertexLocation);

    openglContext->functions()->glBindBuffer(GL_ARRAY_BUFFER,_vboColor);

    int colorLocation = _shaders.attributeLocation("vertexColor");
    openglContext->functions()->glVertexAttribPointer(colorLocation,4,GL_FLOAT,FALSE,0, 0);
    openglContext->functions()->glEnableVertexAttribArray(colorLocation);

    for(int i =0; i < _indices.size(); ++i){
        if ( _indices[i]._geomtype == itLINE){
            glDrawArrays(GL_LINE_STRIP,_indices[i]._start,_indices[i]._count);
        } else if ( _indices[i]._geomtype == itPOLYGON ){
            glDrawArrays(GL_TRIANGLE_FAN,_indices[i]._start,_indices[i]._count);
        }
    }

    openglContext->functions()->glBindBuffer(GL_ARRAY_BUFFER, 0);
    openglContext->functions()->glDisableVertexAttribArray(colorLocation);
    openglContext->functions()->glDisableVertexAttribArray(vertexLocation);

    _shaders.release();

    return true;
}
<|endoftext|>