<commit_before>// Copyright 2016 Chrome 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 "chrome/browser/ui/webui/chrome_web_ui_controller_factory.h"

#include "base/files/file_util.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/url_constants.h"
#include "components/favicon/core/favicon_service.h"
#include "content/browser/webui/web_ui_impl.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/url_data_source.h"
#include "content/public/browser/web_ui.h"
#include "content/public/browser/web_ui_controller.h"
#include "net/base/filename_util.h"
#include "net/base/mime_util.h"
#include "net/url_request/url_fetcher.h"
#include "net/url_request/url_fetcher_delegate.h"
#include "net/url_request/url_request.h"
#include "url/gurl.h"

using content::BrowserThread;
using content::WebUI;
using content::WebUIController;

namespace {

const char kHttpNotFound[] = "HTTP/1.1 404 Not Found\n\n";

class BraveDataSource : public content::URLDataSource,
                        public net::URLFetcherDelegate {
 public:
  BraveDataSource(
    net::URLRequestContextGetter* request_context)
    : request_context_(request_context) {
  }

  // content::URLDataSource implementation.
  std::string GetSource() const override {
    return "brave";
  }

  void StartDataRequest(
      const std::string& path,
      const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
      const GotDataCallback& callback) override {
    GURL url = GURL("file:///" + path);
    if (!url.is_valid()) {
      DLOG(WARNING) << "Invalid webui resource: brave://" << path;
      callback.Run(
          new base::RefCountedStaticMemory(kHttpNotFound, strlen(kHttpNotFound)));
      return;
    }
    net::URLFetcher* fetcher =
        net::URLFetcher::Create(url, net::URLFetcher::GET, this).release();
    pending_[fetcher] = callback;
    fetcher->SetRequestContext(request_context_.get());
    fetcher->Start();
  }

  void OnURLFetchComplete(const net::URLFetcher* source) {
    DCHECK(source);
    PendingRequestsMap::iterator it = pending_.find(source);
    DCHECK(it != pending_.end());
    std::string response;
    source->GetResponseAsString(&response);
    delete source;
    it->second.Run(base::RefCountedString::TakeString(&response));
    pending_.erase(it);
  }

  std::string GetMimeType(const std::string& path) const override {
    const GURL url("file:///" + path);

    std::string mime_type;
    base::FilePath file_path;
    if (!net::FileURLToFilePath(url, &file_path) ||
        !net::GetMimeTypeFromFile(file_path, &mime_type)) {
      DLOG(WARNING) << "Could not get mime type for: file://" << path;
    }

    return mime_type;
  }

  bool ShouldAddContentSecurityPolicy() const override {
    return false;
  }

  bool ShouldDenyXFrameOptions() const override {
    return false;
  }

  bool ShouldServeMimeTypeAsContentTypeHeader() const override {
    return true;
  }

  bool ShouldServiceRequest(const net::URLRequest* request) const override {
    GURL url = request->url();
    return url.SchemeIs(content::kChromeUIScheme) && url.host() == "brave";
  }

 private:
  ~BraveDataSource() override {}
  scoped_refptr<net::URLRequestContextGetter> request_context_;

  using PendingRequestsMap = std::map<const net::URLFetcher*, GotDataCallback>;
  PendingRequestsMap pending_;

  DISALLOW_COPY_AND_ASSIGN(BraveDataSource);
};

class BraveWebUIController : public WebUIController {
 public:
  BraveWebUIController(WebUI* web_ui) : WebUIController(web_ui) {
    Profile* profile = Profile::FromWebUI(web_ui);
    content::URLDataSource::Add(
        profile,
        new BraveDataSource(profile->GetRequestContext()));
  }
  bool OverrideHandleWebUIMessage(const GURL& source_url,
                                  const std::string& message,
                                  const base::ListValue& args) override {
    return false;
  }

  void RenderViewCreated(content::RenderViewHost* render_view_host) {}
};

typedef WebUIController* (*WebUIFactoryFunction)(WebUI* web_ui,
                                                 const GURL& url);

// Template for defining WebUIFactoryFunction.
template<class T>
WebUIController* NewWebUI(WebUI* web_ui, const GURL& url) {
  return new T(web_ui);
}

WebUIFactoryFunction GetWebUIFactoryFunction(WebUI* web_ui,
                                             Profile* profile,
                                             const GURL& url) {
  if (!url.SchemeIs(content::kChromeUIScheme)) {
    return NULL;
  }

  if (url.host() == "brave") {
    return &NewWebUI<BraveWebUIController>;
  }

  return NULL;
}

}  // namespace

WebUI::TypeID ChromeWebUIControllerFactory::GetWebUIType(
      content::BrowserContext* browser_context, const GURL& url) const {
  Profile* profile = Profile::FromBrowserContext(browser_context);
  WebUIFactoryFunction function = GetWebUIFactoryFunction(NULL, profile, url);
  return function ? reinterpret_cast<WebUI::TypeID>(function) : WebUI::kNoWebUI;
}

bool ChromeWebUIControllerFactory::UseWebUIForURL(
    content::BrowserContext* browser_context, const GURL& url) const {
  return GetWebUIType(browser_context, url) != WebUI::kNoWebUI;
}

bool ChromeWebUIControllerFactory::UseWebUIBindingsForURL(
    content::BrowserContext* browser_context, const GURL& url) const {
  return UseWebUIForURL(browser_context, url);
}

WebUIController*
ChromeWebUIControllerFactory::CreateWebUIControllerForURL(
    WebUI* web_ui,
    const GURL& url) const {
  Profile* profile = Profile::FromWebUI(web_ui);
  WebUIFactoryFunction function = GetWebUIFactoryFunction(web_ui, profile, url);
  if (!function)
    return NULL;

  return (*function)(web_ui, url);
}

// static
ChromeWebUIControllerFactory* ChromeWebUIControllerFactory::GetInstance() {
  return base::Singleton<ChromeWebUIControllerFactory>::get();
}

ChromeWebUIControllerFactory::ChromeWebUIControllerFactory() {
}

ChromeWebUIControllerFactory::~ChromeWebUIControllerFactory() {
}

void ChromeWebUIControllerFactory::GetFaviconForURL(
    Profile* profile,
    const GURL& page_url,
    const std::vector<int>& desired_sizes_in_pixel,
    const favicon_base::FaviconResultsCallback& callback) const {
  std::vector<favicon_base::FaviconRawBitmapResult>* results =
      new std::vector<favicon_base::FaviconRawBitmapResult>();

  base::ThreadTaskRunnerHandle::Get()->PostTask(
      FROM_HERE,
      base::Bind(&favicon::FaviconService::FaviconResultsCallbackRunner,
                 callback, base::Owned(results)));

}
<commit_msg>don’t replace the data source otherwise pending requests will be lost fix https://github.com/brave/browser-laptop/issues/9352 auditors @bbondy @darkdh<commit_after>// Copyright 2016 Chrome 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 "chrome/browser/ui/webui/chrome_web_ui_controller_factory.h"

#include "base/files/file_util.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/url_constants.h"
#include "components/favicon/core/favicon_service.h"
#include "content/browser/webui/web_ui_impl.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/url_data_source.h"
#include "content/public/browser/web_ui.h"
#include "content/public/browser/web_ui_controller.h"
#include "net/base/filename_util.h"
#include "net/base/mime_util.h"
#include "net/url_request/url_fetcher.h"
#include "net/url_request/url_fetcher_delegate.h"
#include "net/url_request/url_request.h"
#include "url/gurl.h"

using content::BrowserThread;
using content::WebUI;
using content::WebUIController;

namespace {

const char kHttpNotFound[] = "HTTP/1.1 404 Not Found\n\n";

class BraveDataSource : public content::URLDataSource,
                        public net::URLFetcherDelegate {
 public:
  BraveDataSource(
    net::URLRequestContextGetter* request_context)
    : request_context_(request_context) {
  }

  // content::URLDataSource implementation.
  std::string GetSource() const override {
    return "brave";
  }

  void StartDataRequest(
      const std::string& path,
      const content::ResourceRequestInfo::WebContentsGetter& wc_getter,
      const GotDataCallback& callback) override {
    GURL url = GURL("file:///" + path);
    if (!url.is_valid()) {
      DLOG(WARNING) << "Invalid webui resource: brave://" << path;
      callback.Run(
          new base::RefCountedStaticMemory(kHttpNotFound, strlen(kHttpNotFound)));
      return;
    }
    net::URLFetcher* fetcher =
        net::URLFetcher::Create(url, net::URLFetcher::GET, this).release();
    pending_[fetcher] = callback;
    fetcher->SetRequestContext(request_context_.get());
    fetcher->Start();
  }

  void OnURLFetchComplete(const net::URLFetcher* source) {
    DCHECK(source);
    PendingRequestsMap::iterator it = pending_.find(source);
    DCHECK(it != pending_.end());
    std::string response;
    source->GetResponseAsString(&response);
    delete source;
    it->second.Run(base::RefCountedString::TakeString(&response));
    pending_.erase(it);
  }

  std::string GetMimeType(const std::string& path) const override {
    const GURL url("file:///" + path);

    std::string mime_type;
    base::FilePath file_path;
    if (!net::FileURLToFilePath(url, &file_path) ||
        !net::GetMimeTypeFromFile(file_path, &mime_type)) {
      DLOG(WARNING) << "Could not get mime type for: file://" << path;
    }

    return mime_type;
  }

  bool ShouldReplaceExistingSource() const override {
    return false;
  }

  bool ShouldAddContentSecurityPolicy() const override {
    return false;
  }

  bool ShouldDenyXFrameOptions() const override {
    return false;
  }

  bool ShouldServeMimeTypeAsContentTypeHeader() const override {
    return true;
  }

  bool ShouldServiceRequest(const net::URLRequest* request) const override {
    GURL url = request->url();
    return url.SchemeIs(content::kChromeUIScheme) && url.host() == "brave";
  }

 private:
  ~BraveDataSource() override {}
  scoped_refptr<net::URLRequestContextGetter> request_context_;

  using PendingRequestsMap = std::map<const net::URLFetcher*, GotDataCallback>;
  PendingRequestsMap pending_;

  DISALLOW_COPY_AND_ASSIGN(BraveDataSource);
};

class BraveWebUIController : public WebUIController {
 public:
  BraveWebUIController(WebUI* web_ui) : WebUIController(web_ui) {
    Profile* profile = Profile::FromWebUI(web_ui);
    content::URLDataSource::Add(
        profile,
        new BraveDataSource(profile->GetRequestContext()));
  }
  bool OverrideHandleWebUIMessage(const GURL& source_url,
                                  const std::string& message,
                                  const base::ListValue& args) override {
    return false;
  }

  void RenderViewCreated(content::RenderViewHost* render_view_host) {}
};

typedef WebUIController* (*WebUIFactoryFunction)(WebUI* web_ui,
                                                 const GURL& url);

// Template for defining WebUIFactoryFunction.
template<class T>
WebUIController* NewWebUI(WebUI* web_ui, const GURL& url) {
  return new T(web_ui);
}

WebUIFactoryFunction GetWebUIFactoryFunction(WebUI* web_ui,
                                             Profile* profile,
                                             const GURL& url) {
  if (!url.SchemeIs(content::kChromeUIScheme)) {
    return NULL;
  }

  if (url.host() == "brave") {
    return &NewWebUI<BraveWebUIController>;
  }

  return NULL;
}

}  // namespace

WebUI::TypeID ChromeWebUIControllerFactory::GetWebUIType(
      content::BrowserContext* browser_context, const GURL& url) const {
  Profile* profile = Profile::FromBrowserContext(browser_context);
  WebUIFactoryFunction function = GetWebUIFactoryFunction(NULL, profile, url);
  return function ? reinterpret_cast<WebUI::TypeID>(function) : WebUI::kNoWebUI;
}

bool ChromeWebUIControllerFactory::UseWebUIForURL(
    content::BrowserContext* browser_context, const GURL& url) const {
  return GetWebUIType(browser_context, url) != WebUI::kNoWebUI;
}

bool ChromeWebUIControllerFactory::UseWebUIBindingsForURL(
    content::BrowserContext* browser_context, const GURL& url) const {
  return UseWebUIForURL(browser_context, url);
}

WebUIController*
ChromeWebUIControllerFactory::CreateWebUIControllerForURL(
    WebUI* web_ui,
    const GURL& url) const {
  Profile* profile = Profile::FromWebUI(web_ui);
  WebUIFactoryFunction function = GetWebUIFactoryFunction(web_ui, profile, url);
  if (!function)
    return NULL;

  return (*function)(web_ui, url);
}

// static
ChromeWebUIControllerFactory* ChromeWebUIControllerFactory::GetInstance() {
  return base::Singleton<ChromeWebUIControllerFactory>::get();
}

ChromeWebUIControllerFactory::ChromeWebUIControllerFactory() {
}

ChromeWebUIControllerFactory::~ChromeWebUIControllerFactory() {
}

void ChromeWebUIControllerFactory::GetFaviconForURL(
    Profile* profile,
    const GURL& page_url,
    const std::vector<int>& desired_sizes_in_pixel,
    const favicon_base::FaviconResultsCallback& callback) const {
  std::vector<favicon_base::FaviconRawBitmapResult>* results =
      new std::vector<favicon_base::FaviconRawBitmapResult>();

  base::ThreadTaskRunnerHandle::Get()->PostTask(
      FROM_HERE,
      base::Bind(&favicon::FaviconService::FaviconResultsCallbackRunner,
                 callback, base::Owned(results)));

}
<|endoftext|>


<commit_before>// @(#)root/net:$Name:  $:$Id: TNetFile.cxx,v 1.6 2000/09/06 14:10:17 rdm Exp $
// Author: Fons Rademakers   14/08/97

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TNetFile                                                             //
//                                                                      //
// A TNetFile is like a normal TFile except that it reads and writes    //
// its data via a rootd server (for more on the rootd daemon see the    //
// source files root/rootd/src/*.cxx). TNetFile file names are in       //
// standard URL format with protocol "root" or "roots". The following   //
// are valid TNetFile URL's:                                            //
//                                                                      //
//    roots://hpsalo/files/aap.root                                     //
//    root://hpbrun.cern.ch/root/hsimple.root                           //
//    root://pcna49a:5151/~na49/data/run821.root                        //
//    root://pcna49d.cern.ch:5050//v1/data/run810.root                  //
//                                                                      //
// The only difference with the well known httpd URL's is that the root //
// of the remote file tree is the user's home directory. Therefore an   //
// absolute pathname requires a // after the host or port specifier     //
// (see last example). Further the expansion of the standard shell      //
// characters, like ~, $, .., are handled as expected.                  //
// TNetFile (actually TUrl) uses 1094 as default port for rootd.        //
//                                                                      //
// Connecting to a rootd requires the remote user id and password.      //
// TNetFile allows three ways for you to provide your login:            //
//   1) Setting it globally via the static functions:                   //
//          TNetFile::SetUser() and TNetFile::SetPasswd()               //
//   2) Getting it from the ~/.netrc file (same file as used by ftp)    //
//   3) Command line prompt                                             //
// The different methods will be tried in the order given above.        //
// On machines with AFS rootd will authenticate using AFS (if it was    //
// compiled with AFS support).                                          //
//                                                                      //
// If the protocol was specified as "roots" a secure authetication      //
// method will be used. The secure method uses the SRP, Secure Remote   //
// Passwords, package. SRP uses a so called "asymmetric key exchange    //
// protocol" in which no passwords are ever send over the wire. This    //
// protocol is safe against all known security attacks. For more see:   //
// Begin_Html NetFile //
// End_Html                                                             //
//                                                                      //
// The rootd daemon lives in the directory $ROOTSYS/bin. It can be      //
// started either via inetd or by hand from the command line (no need   //
// to be super user). For more info about rootd see the web page:       //
// Begin_Html NetFile //
// End_Html                                                             //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include <errno.h>

#include "TNetFile.h"
#include "TAuthenticate.h"
#include "TROOT.h"
#include "TSocket.h"
#include "TSystem.h"
#include "TApplication.h"
#include "TSysEvtHandler.h"
#include "Bytes.h"

// Must match order of ERootdErrors enum define in rootd.h
const char *kRootdErrStr[] = {
   "undefined error",
   "file not found",
   "error in file name",
   "file already exists",
   "no access to file",
   "error opening file",
   "file already opened in read or write mode",
   "file already opened in write mode",
   "no more space on device",
   "bad op code",
   "bad message",
   "error writing to file",
   "error reading from file",
   "no such user",
   "remote not setup for anonymous access",
   "illegal user name",
   "can't cd to home directory",
   "can't get passwd info",
   "wrong passwd",
   "no SRP support in remote daemon",
   "fatal error"
};

ClassImp(TNetFile)

//______________________________________________________________________________
TNetFile::TNetFile(const char *url, Option_t *option, const char *ftitle, Int_t compress)
         : TFile(url, "NET", ftitle, compress), fUrl(url)
{
   // Create a NetFile object. A net file is the same as a TFile
   // except that it is being accessed via a rootd server. The url
   // argument must be of the form: root[s]://host.dom.ain/file.root.
   // When protocol is "roots" try using secure authentication.
   // If the file specified in the URL does not exist, is not accessable
   // or can not be created the kZombie bit will be set in the TNetFile
   // object. Use IsZombie() to see if the file is accessable.
   // If the remote daemon thinks the file is still connected, while you are
   // sure this is not the case you can force open the file by preceding the
   // option argument with an "f" or "F" , e.g.: "frecreate". Do this only
   // in cases when you are very sure nobody else is using the file.
   // For a description of the option and other arguments see the TFile ctor.
   // The preferred interface to this constructor is via TFile::Open().

   TAuthenticate *auth;

   fOffset = 0;

   Bool_t forceOpen = kFALSE;
   if (option[0] == 'F' || option[0] == 'f') {
      fOption   = &option[1];
      forceOpen = kTRUE;
   } else
      fOption = option;

   Bool_t create = kFALSE;
   if (!fOption.CompareTo("NEW", TString::kIgnoreCase) ||
       !fOption.CompareTo("CREATE", TString::kIgnoreCase) ||
       !fOption.CompareTo("RECREATE", TString::kIgnoreCase))
       create = kTRUE;
   Bool_t update = fOption.CompareTo("UPDATE", TString::kIgnoreCase)
                   ? kFALSE : kTRUE;
   Bool_t read   = fOption.CompareTo("READ", TString::kIgnoreCase)
                   ? kFALSE : kTRUE;
   if (!create && !update && !read) {
      read    = kTRUE;
      fOption = "READ";
   }

   if (!fUrl.IsValid()) {
      Error("TNetFile", "invalid URL specified: %s", fUrl.GetUrl());
      goto zombie;
   }

   // Open connection to remote rootd server
   fSocket = new TSocket(fUrl.GetHost(), fUrl.GetPort());
   if (!fSocket->IsValid()) {
      Error("TNetFile", "can't open connection to rootd on host %s at port %d",
            fUrl.GetHost(), fUrl.GetPort());
      goto zombie;
   }

   // Set some socket options
   fSocket->SetOption(kNoDelay, 1);
   fSocket->SetOption(kSendBuffer, 65536);
   fSocket->SetOption(kRecvBuffer, 65536);

   // Authenticate to remote rootd server
   auth = new TAuthenticate(fSocket, fUrl.GetProtocol(), fUrl.GetHost());
   if (!auth->Authenticate(fUser)) {
      if (!strcmp(fUrl.GetProtocol(), "roots"))
         Error("TNetFile", "secure authentication failed for host %s", fUrl.GetHost());
      else
         Error("TNetFile", "authentication failed for host %s", fUrl.GetHost());
      delete auth;
      goto zombie;
   }
   delete auth;

   if (forceOpen)
      fSocket->Send(Form("%s %s", fUrl.GetFile(), ToLower("f"+fOption).Data()), kROOTD_OPEN);
   else
      fSocket->Send(Form("%s %s", fUrl.GetFile(), ToLower(fOption).Data()), kROOTD_OPEN);

   int           stat;
   EMessageTypes kind;

   Recv(stat, kind);

   if (kind == kROOTD_ERR) {
      PrintError("TNetFile", stat);
      goto zombie;
   }

   if (stat == 1)
      fWritable = kTRUE;
   else
      fWritable = kFALSE;

   Init(create);

   return;

zombie:
   // error in file opening occured, make this object a zombie
   MakeZombie();
   SafeDelete(fSocket);
   gDirectory = gROOT;
}

//______________________________________________________________________________
TNetFile::~TNetFile()
{
   // TNetFile dtor. Send close message and close socket.

   Close();
   SafeDelete(fSocket);
}

//______________________________________________________________________________
void TNetFile::Close(Option_t *opt)
{
   // Close remote file.

   if (!fSocket) return;

   TFile::Close(opt);
   fSocket->Send(kROOTD_CLOSE);
}

//______________________________________________________________________________
void TNetFile::Flush()
{
   // Flush file to disk.

   if (fSocket && fWritable)
      fSocket->Send(kROOTD_FLUSH);
}

//______________________________________________________________________________
void TNetFile::Init(Bool_t create)
{
   // Initialize a TNetFile object.

   Seek(0);

   TFile::Init(create);
   fD = -2;   // so TFile::IsOpen() will return true when in TFile::~TFile
}

//______________________________________________________________________________
Bool_t TNetFile::IsOpen() const
{
   // Retruns kTRUE if file is open, kFALSE otherwise.

   return fSocket == 0 ? kFALSE : kTRUE;
}

//______________________________________________________________________________
void TNetFile::Print(Option_t *)
{
   // Print some info about the net file.

   const char *fname = fUrl.GetFile();
   Printf("URL:           %s", fUrl.GetUrl());
   Printf("Remote file:   %s", &fname[1]);
   Printf("Remote user:   %s", fUser.Data());
   Printf("Title:         %s", fTitle.Data());
   Printf("Option:        %s", fOption.Data());
   Printf("Bytes written: %g", fBytesWrite);
   Printf("Bytes read:    %g", fBytesRead);
}

//______________________________________________________________________________
void TNetFile::PrintError(const char *where, Int_t err)
{
   // Print error string depending on error code.

   Error(where, kRootdErrStr[err]);
}

//______________________________________________________________________________
Bool_t TNetFile::ReadBuffer(char *buf, int len)
{
   // Read specified byte range from remote file via rootd daemon.
   // Returns kTRUE in case of error.

   if (!fSocket) return kTRUE;

   Bool_t result = kFALSE;

   if (gApplication && gApplication->GetSignalHandler())
      gApplication->GetSignalHandler()->Delay();

   if (fSocket->Send(Form("%d %d", fOffset, len), kROOTD_GET) < 0) {
      Error("ReadBuffer", "error sending kROOTD_GET command");
      result = kTRUE;
      goto end;
   }

   Int_t         stat, n;
   EMessageTypes kind;

   n = Recv(stat, kind);

   if (kind == kROOTD_ERR || n < 0) {
      PrintError("ReadBuffer", stat);
      result = kTRUE;
      goto end;
   }

   while ((n = fSocket->RecvRaw(buf, len)) < 0 && TSystem::GetErrno() == EINTR)
      TSystem::ResetErrno();

   if (n != len) {
      Error("ReadBuffer", "error receiving buffer of length %d, got %d", len, n);
      result = kTRUE;
      goto end;
   }

   fOffset += len;

   fBytesRead  += len;
#ifdef WIN32
   SetFileBytesRead(GetFileBytesRead() + len);
#else
   fgBytesRead += len;
#endif

end:
   if (gApplication && gApplication->GetSignalHandler())
      gApplication->GetSignalHandler()->HandleDelayedSignal();

   return result;
}

//______________________________________________________________________________
Bool_t TNetFile::WriteBuffer(const char *buf, int len)
{
   // Write specified byte range to remote file via rootd daemon.
   // Returns kTRUE in case of error.

   if (!fSocket || !fWritable) return kTRUE;

   Bool_t result = kFALSE;

   gSystem->IgnoreInterrupt();

   if (fSocket->Send(Form("%d %d", fOffset, len), kROOTD_PUT) < 0) {
      Error("WriteBuffer", "error sending kROOTD_PUT command");
      result = kTRUE;
      goto end;
   }
   if (fSocket->SendRaw(buf, len) < 0) {
      Error("WriteBuffer", "error sending buffer");
      result = kTRUE;
      goto end;
   }

   Int_t         stat, n;
   EMessageTypes kind;

   n = Recv(stat, kind);

   if (kind == kROOTD_ERR || n < 0) {
      PrintError("WriteBuffer", stat);
      result = kTRUE;
      goto end;
   }

   fOffset += len;

   fBytesWrite  += len;
#ifdef WIN32
   SetFileBytesWritten(GetFileBytesWritten() + len);
#else
   fgBytesWrite += len;
#endif

end:
   gSystem->IgnoreInterrupt(kFALSE);

   return result;
}

//______________________________________________________________________________
Int_t TNetFile::Recv(Int_t &status, EMessageTypes &kind)
{
   // Return status from rootd server and message kind. Returns -1 in
   // case of error otherwise 8 (sizeof 2 words, status and kind).

   kind   = kROOTD_ERR;
   status = 0;

   if (!fSocket) return -1;

   Int_t what;
   Int_t n = fSocket->Recv(status, what);
   kind = (EMessageTypes) what;
   return n;
}

//______________________________________________________________________________
void TNetFile::Seek(Seek_t offset, ERelativeTo pos)
{
   // Set position from where to start reading.

   switch (pos) {
   case kBeg:
      fOffset = offset;
      break;
   case kCur:
      fOffset += offset;
      break;
   case kEnd:
      fOffset = fEND - offset;  // is fEND really EOF or logical EOF?
      break;
   }
}
<commit_msg>fixed error message.<commit_after>// @(#)root/net:$Name:  $:$Id: TNetFile.cxx,v 1.7 2000/11/27 10:47:26 rdm Exp $
// Author: Fons Rademakers   14/08/97

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TNetFile                                                             //
//                                                                      //
// A TNetFile is like a normal TFile except that it reads and writes    //
// its data via a rootd server (for more on the rootd daemon see the    //
// source files root/rootd/src/*.cxx). TNetFile file names are in       //
// standard URL format with protocol "root" or "roots". The following   //
// are valid TNetFile URL's:                                            //
//                                                                      //
//    roots://hpsalo/files/aap.root                                     //
//    root://hpbrun.cern.ch/root/hsimple.root                           //
//    root://pcna49a:5151/~na49/data/run821.root                        //
//    root://pcna49d.cern.ch:5050//v1/data/run810.root                  //
//                                                                      //
// The only difference with the well known httpd URL's is that the root //
// of the remote file tree is the user's home directory. Therefore an   //
// absolute pathname requires a // after the host or port specifier     //
// (see last example). Further the expansion of the standard shell      //
// characters, like ~, $, .., are handled as expected.                  //
// TNetFile (actually TUrl) uses 1094 as default port for rootd.        //
//                                                                      //
// Connecting to a rootd requires the remote user id and password.      //
// TNetFile allows three ways for you to provide your login:            //
//   1) Setting it globally via the static functions:                   //
//          TNetFile::SetUser() and TNetFile::SetPasswd()               //
//   2) Getting it from the ~/.netrc file (same file as used by ftp)    //
//   3) Command line prompt                                             //
// The different methods will be tried in the order given above.        //
// On machines with AFS rootd will authenticate using AFS (if it was    //
// compiled with AFS support).                                          //
//                                                                      //
// If the protocol was specified as "roots" a secure authetication      //
// method will be used. The secure method uses the SRP, Secure Remote   //
// Passwords, package. SRP uses a so called "asymmetric key exchange    //
// protocol" in which no passwords are ever send over the wire. This    //
// protocol is safe against all known security attacks. For more see:   //
// Begin_Html NetFile //
// End_Html                                                             //
//                                                                      //
// The rootd daemon lives in the directory $ROOTSYS/bin. It can be      //
// started either via inetd or by hand from the command line (no need   //
// to be super user). For more info about rootd see the web page:       //
// Begin_Html NetFile //
// End_Html                                                             //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include <errno.h>

#include "TNetFile.h"
#include "TAuthenticate.h"
#include "TROOT.h"
#include "TSocket.h"
#include "TSystem.h"
#include "TApplication.h"
#include "TSysEvtHandler.h"
#include "Bytes.h"

// Must match order of ERootdErrors enum define in rootd.h
const char *kRootdErrStr[] = {
   "undefined error",
   "file not found",
   "error in file name",
   "file already exists",
   "no access to file",
   "error opening file",
   "file already opened in read or write mode",
   "file already opened in write mode",
   "no more space on device",
   "bad op code",
   "bad message",
   "error writing to file",
   "error reading from file",
   "no such user",
   "remote not setup for anonymous access",
   "illegal user name",
   "can't cd to home directory",
   "can't get passwd info",
   "wrong passwd",
   "no SRP support in remote daemon",
   "fatal error"
};

ClassImp(TNetFile)

//______________________________________________________________________________
TNetFile::TNetFile(const char *url, Option_t *option, const char *ftitle, Int_t compress)
         : TFile(url, "NET", ftitle, compress), fUrl(url)
{
   // Create a NetFile object. A net file is the same as a TFile
   // except that it is being accessed via a rootd server. The url
   // argument must be of the form: root[s]://host.dom.ain/file.root.
   // When protocol is "roots" try using secure authentication.
   // If the file specified in the URL does not exist, is not accessable
   // or can not be created the kZombie bit will be set in the TNetFile
   // object. Use IsZombie() to see if the file is accessable.
   // If the remote daemon thinks the file is still connected, while you are
   // sure this is not the case you can force open the file by preceding the
   // option argument with an "f" or "F" , e.g.: "frecreate". Do this only
   // in cases when you are very sure nobody else is using the file.
   // For a description of the option and other arguments see the TFile ctor.
   // The preferred interface to this constructor is via TFile::Open().

   TAuthenticate *auth;

   fOffset = 0;

   Bool_t forceOpen = kFALSE;
   if (option[0] == 'F' || option[0] == 'f') {
      fOption   = &option[1];
      forceOpen = kTRUE;
   } else
      fOption = option;

   Bool_t create = kFALSE;
   if (!fOption.CompareTo("NEW", TString::kIgnoreCase) ||
       !fOption.CompareTo("CREATE", TString::kIgnoreCase) ||
       !fOption.CompareTo("RECREATE", TString::kIgnoreCase))
       create = kTRUE;
   Bool_t update = fOption.CompareTo("UPDATE", TString::kIgnoreCase)
                   ? kFALSE : kTRUE;
   Bool_t read   = fOption.CompareTo("READ", TString::kIgnoreCase)
                   ? kFALSE : kTRUE;
   if (!create && !update && !read) {
      read    = kTRUE;
      fOption = "READ";
   }

   if (!fUrl.IsValid()) {
      Error("TNetFile", "invalid URL specified: %s", url);
      goto zombie;
   }

   // Open connection to remote rootd server
   fSocket = new TSocket(fUrl.GetHost(), fUrl.GetPort());
   if (!fSocket->IsValid()) {
      Error("TNetFile", "can't open connection to rootd on host %s at port %d",
            fUrl.GetHost(), fUrl.GetPort());
      goto zombie;
   }

   // Set some socket options
   fSocket->SetOption(kNoDelay, 1);
   fSocket->SetOption(kSendBuffer, 65536);
   fSocket->SetOption(kRecvBuffer, 65536);

   // Authenticate to remote rootd server
   auth = new TAuthenticate(fSocket, fUrl.GetProtocol(), fUrl.GetHost());
   if (!auth->Authenticate(fUser)) {
      if (!strcmp(fUrl.GetProtocol(), "roots"))
         Error("TNetFile", "secure authentication failed for host %s", fUrl.GetHost());
      else
         Error("TNetFile", "authentication failed for host %s", fUrl.GetHost());
      delete auth;
      goto zombie;
   }
   delete auth;

   if (forceOpen)
      fSocket->Send(Form("%s %s", fUrl.GetFile(), ToLower("f"+fOption).Data()), kROOTD_OPEN);
   else
      fSocket->Send(Form("%s %s", fUrl.GetFile(), ToLower(fOption).Data()), kROOTD_OPEN);

   int           stat;
   EMessageTypes kind;

   Recv(stat, kind);

   if (kind == kROOTD_ERR) {
      PrintError("TNetFile", stat);
      goto zombie;
   }

   if (stat == 1)
      fWritable = kTRUE;
   else
      fWritable = kFALSE;

   Init(create);

   return;

zombie:
   // error in file opening occured, make this object a zombie
   MakeZombie();
   SafeDelete(fSocket);
   gDirectory = gROOT;
}

//______________________________________________________________________________
TNetFile::~TNetFile()
{
   // TNetFile dtor. Send close message and close socket.

   Close();
   SafeDelete(fSocket);
}

//______________________________________________________________________________
void TNetFile::Close(Option_t *opt)
{
   // Close remote file.

   if (!fSocket) return;

   TFile::Close(opt);
   fSocket->Send(kROOTD_CLOSE);
}

//______________________________________________________________________________
void TNetFile::Flush()
{
   // Flush file to disk.

   if (fSocket && fWritable)
      fSocket->Send(kROOTD_FLUSH);
}

//______________________________________________________________________________
void TNetFile::Init(Bool_t create)
{
   // Initialize a TNetFile object.

   Seek(0);

   TFile::Init(create);
   fD = -2;   // so TFile::IsOpen() will return true when in TFile::~TFile
}

//______________________________________________________________________________
Bool_t TNetFile::IsOpen() const
{
   // Retruns kTRUE if file is open, kFALSE otherwise.

   return fSocket == 0 ? kFALSE : kTRUE;
}

//______________________________________________________________________________
void TNetFile::Print(Option_t *)
{
   // Print some info about the net file.

   const char *fname = fUrl.GetFile();
   Printf("URL:           %s", fUrl.GetUrl());
   Printf("Remote file:   %s", &fname[1]);
   Printf("Remote user:   %s", fUser.Data());
   Printf("Title:         %s", fTitle.Data());
   Printf("Option:        %s", fOption.Data());
   Printf("Bytes written: %g", fBytesWrite);
   Printf("Bytes read:    %g", fBytesRead);
}

//______________________________________________________________________________
void TNetFile::PrintError(const char *where, Int_t err)
{
   // Print error string depending on error code.

   Error(where, kRootdErrStr[err]);
}

//______________________________________________________________________________
Bool_t TNetFile::ReadBuffer(char *buf, int len)
{
   // Read specified byte range from remote file via rootd daemon.
   // Returns kTRUE in case of error.

   if (!fSocket) return kTRUE;

   Bool_t result = kFALSE;

   if (gApplication && gApplication->GetSignalHandler())
      gApplication->GetSignalHandler()->Delay();

   if (fSocket->Send(Form("%d %d", fOffset, len), kROOTD_GET) < 0) {
      Error("ReadBuffer", "error sending kROOTD_GET command");
      result = kTRUE;
      goto end;
   }

   Int_t         stat, n;
   EMessageTypes kind;

   n = Recv(stat, kind);

   if (kind == kROOTD_ERR || n < 0) {
      PrintError("ReadBuffer", stat);
      result = kTRUE;
      goto end;
   }

   while ((n = fSocket->RecvRaw(buf, len)) < 0 && TSystem::GetErrno() == EINTR)
      TSystem::ResetErrno();

   if (n != len) {
      Error("ReadBuffer", "error receiving buffer of length %d, got %d", len, n);
      result = kTRUE;
      goto end;
   }

   fOffset += len;

   fBytesRead  += len;
#ifdef WIN32
   SetFileBytesRead(GetFileBytesRead() + len);
#else
   fgBytesRead += len;
#endif

end:
   if (gApplication && gApplication->GetSignalHandler())
      gApplication->GetSignalHandler()->HandleDelayedSignal();

   return result;
}

//______________________________________________________________________________
Bool_t TNetFile::WriteBuffer(const char *buf, int len)
{
   // Write specified byte range to remote file via rootd daemon.
   // Returns kTRUE in case of error.

   if (!fSocket || !fWritable) return kTRUE;

   Bool_t result = kFALSE;

   gSystem->IgnoreInterrupt();

   if (fSocket->Send(Form("%d %d", fOffset, len), kROOTD_PUT) < 0) {
      Error("WriteBuffer", "error sending kROOTD_PUT command");
      result = kTRUE;
      goto end;
   }
   if (fSocket->SendRaw(buf, len) < 0) {
      Error("WriteBuffer", "error sending buffer");
      result = kTRUE;
      goto end;
   }

   Int_t         stat, n;
   EMessageTypes kind;

   n = Recv(stat, kind);

   if (kind == kROOTD_ERR || n < 0) {
      PrintError("WriteBuffer", stat);
      result = kTRUE;
      goto end;
   }

   fOffset += len;

   fBytesWrite  += len;
#ifdef WIN32
   SetFileBytesWritten(GetFileBytesWritten() + len);
#else
   fgBytesWrite += len;
#endif

end:
   gSystem->IgnoreInterrupt(kFALSE);

   return result;
}

//______________________________________________________________________________
Int_t TNetFile::Recv(Int_t &status, EMessageTypes &kind)
{
   // Return status from rootd server and message kind. Returns -1 in
   // case of error otherwise 8 (sizeof 2 words, status and kind).

   kind   = kROOTD_ERR;
   status = 0;

   if (!fSocket) return -1;

   Int_t what;
   Int_t n = fSocket->Recv(status, what);
   kind = (EMessageTypes) what;
   return n;
}

//______________________________________________________________________________
void TNetFile::Seek(Seek_t offset, ERelativeTo pos)
{
   // Set position from where to start reading.

   switch (pos) {
   case kBeg:
      fOffset = offset;
      break;
   case kCur:
      fOffset += offset;
      break;
   case kEnd:
      fOffset = fEND - offset;  // is fEND really EOF or logical EOF?
      break;
   }
}
<|endoftext|>


<commit_before>/*
 * medViewerToolBoxViewProperties.cpp
 *
 *  Created on: 15 févr. 2011
 *      Author: aabadie
 */

#include <medViewerToolBoxViewProperties.h>

#include <medCore/medAbstractView.h>
#include <medGui/medToolBoxTab.h>

class medViewerToolBoxViewPropertiesPrivate
{
    public:
        medAbstractView *view;
        QWidget* propertiesToolBoxWidget;
        QComboBox * dataComboBox;
        QComboBox * lutComboBox;
        QCheckBox * visible;
        QDoubleSpinBox * opacity;
        QSlider * opacitySlider;
};

medViewerToolBoxViewProperties::medViewerToolBoxViewProperties(QWidget *parent) :
    medToolBox(parent), d(new medViewerToolBoxViewPropertiesPrivate)
{
    d->view = 0;
    d->dataComboBox = new QComboBox(this);
    d->dataComboBox->setFocusPolicy(Qt::NoFocus);

    d->lutComboBox = new QComboBox(this);
    d->lutComboBox->setFocusPolicy(Qt::NoFocus);
    d->lutComboBox->addItem("Default");
    d->lutComboBox->addItem("Black & White");
    d->lutComboBox->addItem("Black & White Inversed");
    d->lutComboBox->addItem("Spectrum");
    d->lutComboBox->addItem("Hot Metal");
    d->lutComboBox->addItem("Hot Green");
    d->lutComboBox->addItem("Hot Iron");
    d->lutComboBox->addItem("GE");
    d->lutComboBox->addItem("Flow");
    d->lutComboBox->addItem("Loni");
    d->lutComboBox->addItem("Loni 2");
    d->lutComboBox->addItem("Asymmetry");
    d->lutComboBox->addItem("P-Value");
    d->lutComboBox->addItem("Red Black Alpha");
    d->lutComboBox->addItem("Green Black Alpha");
    d->lutComboBox->addItem("Blue Black Alpha");
    d->lutComboBox->addItem("Muscles & Bones");
    d->lutComboBox->addItem("Bones");
    d->lutComboBox->addItem("Red Vessels");
    d->lutComboBox->addItem("Cardiac");
    d->lutComboBox->addItem("Gray Rainbow");
    d->lutComboBox->addItem("Stern");
    d->lutComboBox->addItem("Black Body");

    d->visible = new QCheckBox(this);

    d->opacitySlider = new QSlider(this);
    d->opacitySlider->setRange(0, 100);
    d->opacitySlider->setValue(100);
    d->opacitySlider->setOrientation(Qt::Horizontal);

    d->opacity = new QDoubleSpinBox(this);
    d->opacity->setRange(0.0, 1.0);
    d->opacity->setSingleStep(0.01);
    d->opacity->setValue(1.0);

    d->propertiesToolBoxWidget = new QWidget;
    d->propertiesToolBoxWidget->setEnabled(false);

    QHBoxLayout * opacityLayout = new QHBoxLayout;
    opacityLayout->addWidget(d->opacitySlider);
    opacityLayout->addWidget(d->opacity);

    QFormLayout * viewPropertiesLayout = new QFormLayout(d->propertiesToolBoxWidget);
    viewPropertiesLayout->addRow("Select data :", d->dataComboBox);
    viewPropertiesLayout->addRow("Visible :", d->visible);
    //    viewPropertiesLayout->addRow("Opacity :", d->opacity);
    viewPropertiesLayout->addRow("Opacity :", opacityLayout);
    viewPropertiesLayout->addRow("LUT :", d->lutComboBox);
    viewPropertiesLayout->setFormAlignment(Qt::AlignHCenter);

    this->setTitle("View properties");
    this->addWidget(d->propertiesToolBoxWidget);

    QObject::connect(d->dataComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(onDataSelected(int)));
    QObject::connect(d->visible, SIGNAL(stateChanged(int)), this, SLOT(onVisibilitySet(int)));
    QObject::connect(d->opacity, SIGNAL(valueChanged(double)), this, SLOT(onOpacitySet(double)));
    QObject::connect(d->opacitySlider, SIGNAL(valueChanged(int)), this, SLOT(onOpacitySliderSet(int)));
    QObject::connect(d->lutComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(onLUTChanged(int)));
}

medViewerToolBoxViewProperties::~medViewerToolBoxViewProperties(void)
{
    delete d;
    d = NULL;
}

void
medViewerToolBoxViewProperties::update(dtkAbstractView *view)
{
    d->view = dynamic_cast<medAbstractView *> (view);

    if (!view)
        return;

    QObject::connect(d->view, SIGNAL(dataAdded(int)), this, SLOT(onDataAdded(int)), Qt::UniqueConnection);
    QObject::connect(d->view, SIGNAL(closed()), this, SLOT(onViewClosed()), Qt::UniqueConnection);
}

void
medViewerToolBoxViewProperties::onDataAdded(int layer)
{
    if (!d->view)
        return;

    d->propertiesToolBoxWidget->setEnabled(true);
    //d->view->setVisibility(1, layer);
    //d->view->setOpacity(1.0, layer); // why forcing visibility and opacity?
    d->visible->setChecked(true);
    d->dataComboBox->insertItem(layer, QString::number(layer));
    d->dataComboBox->blockSignals(true); // if not blocked, combobox slot is called. Is it what is expected?
    d->dataComboBox->setCurrentIndex(layer);
    d->dataComboBox->blockSignals(false);
    d->opacity->blockSignals(true);
    d->opacity->setValue(d->view->opacity(layer));
    d->opacity->blockSignals(false);
    d->opacitySlider->blockSignals(true);
    d->opacitySlider->setValue(d->view->opacity(layer) * 100);
    d->opacitySlider->blockSignals(false);

    d->view->setCurrentLayer(layer);
    d->lutComboBox->blockSignals(true);
    d->lutComboBox->setCurrentIndex(0);
    d->lutComboBox->blockSignals(false);
    d->view->setProperty("LookupTable", "Default");
    d->view->update();
}

void
medViewerToolBoxViewProperties::onViewClosed(void)
{
    qDebug() << "Clear combo box";
    d->dataComboBox->clear();
}

void
medViewerToolBoxViewProperties::onDataSelected(int index)
{
    if (!d->view || (index == -1))
        return;

    // this method should update toolbox's GUI w.r.t selected data settings
    // to me, it should not set data settings (only current layer)
    d->view->setCurrentLayer(index);

    // d->view->setVisibility(d->view->visibility(index), index);

    d->visible->blockSignals(true);
    d->visible->setChecked((d->view->visibility(index) == 1));
    d->visible->blockSignals(false);
    // d->view->setOpacity(d->view->opacity(index), index);

    d->opacity->blockSignals(true);
    d->opacity->setValue(d->view->opacity(index));
    d->opacitySlider->setValue((int) (d->opacity->value() * 100));
    d->opacity->blockSignals(false);
}

void
medViewerToolBoxViewProperties::onVisibilitySet(int state)
{
    if ((!d->view) || (d->dataComboBox->currentIndex() == -1))
        return;

    if (state == Qt::Checked)
        d->view->setVisibility(1, d->dataComboBox->currentIndex());
    else
        d->view->setVisibility(0, d->dataComboBox->currentIndex());
    d->view->update();
}

void
medViewerToolBoxViewProperties::onOpacitySet(double opacity)
{
    if ((!d->view) || (d->dataComboBox->currentIndex() == -1))
        return;

    d->opacitySlider->blockSignals(true);
    d->opacitySlider->setValue((int) (d->opacity->value() * 100));
    d->opacitySlider->blockSignals(false);

    d->view->setOpacity(opacity, d->dataComboBox->currentIndex());
    d->view->update();
}

void
medViewerToolBoxViewProperties::onOpacitySliderSet(int opacity)
{
    if ((!d->view) || (d->dataComboBox->currentIndex() == -1))
        return;

    d->opacity->blockSignals(true);
    double d_opacity = static_cast<double> (opacity) / 100.0;
    d->opacity->setValue(d_opacity);
    d->opacity->blockSignals(false);

    d->view->setOpacity(d_opacity, d->dataComboBox->currentIndex());
    d->view->update();
}

void
medViewerToolBoxViewProperties::onLUTChanged(int index)
{
    if ((!d->view) || (d->dataComboBox->currentIndex() == -1))
        return;

    d->view->setProperty("LookupTable", d->lutComboBox->itemText(index));
    d->view->update();
}

<commit_msg>Connect view closing signal with view properties toolbox<commit_after>/*
 * medViewerToolBoxViewProperties.cpp
 *
 *  Created on: 15 févr. 2011
 *      Author: aabadie
 */

#include <medViewerToolBoxViewProperties.h>

#include <medCore/medAbstractView.h>
#include <medGui/medToolBoxTab.h>

class medViewerToolBoxViewPropertiesPrivate
{
    public:
        medAbstractView *view;
        QWidget* propertiesToolBoxWidget;
        QComboBox * dataComboBox;
        QComboBox * lutComboBox;
        QCheckBox * visible;
        QDoubleSpinBox * opacity;
        QSlider * opacitySlider;
};

medViewerToolBoxViewProperties::medViewerToolBoxViewProperties(QWidget *parent) :
    medToolBox(parent), d(new medViewerToolBoxViewPropertiesPrivate)
{
    d->view = 0;
    d->dataComboBox = new QComboBox(this);
    d->dataComboBox->setFocusPolicy(Qt::NoFocus);

    d->lutComboBox = new QComboBox(this);
    d->lutComboBox->setFocusPolicy(Qt::NoFocus);
    d->lutComboBox->addItem("Default");
    d->lutComboBox->addItem("Black & White");
    d->lutComboBox->addItem("Black & White Inversed");
    d->lutComboBox->addItem("Spectrum");
    d->lutComboBox->addItem("Hot Metal");
    d->lutComboBox->addItem("Hot Green");
    d->lutComboBox->addItem("Hot Iron");
    d->lutComboBox->addItem("GE");
    d->lutComboBox->addItem("Flow");
    d->lutComboBox->addItem("Loni");
    d->lutComboBox->addItem("Loni 2");
    d->lutComboBox->addItem("Asymmetry");
    d->lutComboBox->addItem("P-Value");
    d->lutComboBox->addItem("Red Black Alpha");
    d->lutComboBox->addItem("Green Black Alpha");
    d->lutComboBox->addItem("Blue Black Alpha");
    d->lutComboBox->addItem("Muscles & Bones");
    d->lutComboBox->addItem("Bones");
    d->lutComboBox->addItem("Red Vessels");
    d->lutComboBox->addItem("Cardiac");
    d->lutComboBox->addItem("Gray Rainbow");
    d->lutComboBox->addItem("Stern");
    d->lutComboBox->addItem("Black Body");

    d->visible = new QCheckBox(this);

    d->opacitySlider = new QSlider(this);
    d->opacitySlider->setRange(0, 100);
    d->opacitySlider->setValue(100);
    d->opacitySlider->setOrientation(Qt::Horizontal);

    d->opacity = new QDoubleSpinBox(this);
    d->opacity->setRange(0.0, 1.0);
    d->opacity->setSingleStep(0.01);
    d->opacity->setValue(1.0);

    d->propertiesToolBoxWidget = new QWidget;
    d->propertiesToolBoxWidget->setEnabled(false);

    QHBoxLayout * opacityLayout = new QHBoxLayout;
    opacityLayout->addWidget(d->opacitySlider);
    opacityLayout->addWidget(d->opacity);

    QFormLayout * viewPropertiesLayout = new QFormLayout(d->propertiesToolBoxWidget);
    viewPropertiesLayout->addRow("Select data :", d->dataComboBox);
    viewPropertiesLayout->addRow("Visible :", d->visible);
    //    viewPropertiesLayout->addRow("Opacity :", d->opacity);
    viewPropertiesLayout->addRow("Opacity :", opacityLayout);
    viewPropertiesLayout->addRow("LUT :", d->lutComboBox);
    viewPropertiesLayout->setFormAlignment(Qt::AlignHCenter);

    this->setTitle("View properties");
    this->addWidget(d->propertiesToolBoxWidget);

    QObject::connect(d->dataComboBox,   SIGNAL(currentIndexChanged(int)),       this, SLOT(onDataSelected(int)));
    QObject::connect(d->visible,        SIGNAL(stateChanged(int)),              this, SLOT(onVisibilitySet(int)));
    QObject::connect(d->opacity,        SIGNAL(valueChanged(double)),           this, SLOT(onOpacitySet(double)));
    QObject::connect(d->opacitySlider,  SIGNAL(valueChanged(int)),              this, SLOT(onOpacitySliderSet(int)));
    QObject::connect(d->lutComboBox,    SIGNAL(currentIndexChanged(int)),       this, SLOT(onLUTChanged(int)));
}

medViewerToolBoxViewProperties::~medViewerToolBoxViewProperties(void)
{
    delete d;
    d = NULL;
}

void
medViewerToolBoxViewProperties::update(dtkAbstractView *view)
{
    d->view = dynamic_cast<medAbstractView *> (view);

    if (!d->view)
        return;

    QObject::connect(d->view, SIGNAL(dataAdded(int)), this, SLOT(onDataAdded(int)), Qt::UniqueConnection);
    QObject::connect(d->view, SIGNAL(closing()), this, SLOT(onViewClosed()), Qt::UniqueConnection);
}

void
medViewerToolBoxViewProperties::onDataAdded(int layer)
{
    if (!d->view)
        return;

    d->propertiesToolBoxWidget->setEnabled(true);
    //d->view->setVisibility(1, layer);
    //d->view->setOpacity(1.0, layer); // why forcing visibility and opacity?
    d->visible->setChecked(true);
    d->dataComboBox->insertItem(layer, QString::number(layer));
    d->dataComboBox->blockSignals(true); // if not blocked, combobox slot is called. Is it what is expected?
    d->dataComboBox->setCurrentIndex(layer);
    d->dataComboBox->blockSignals(false);
    d->opacity->blockSignals(true);
    d->opacity->setValue(d->view->opacity(layer));
    d->opacity->blockSignals(false);
    d->opacitySlider->blockSignals(true);
    d->opacitySlider->setValue(d->view->opacity(layer) * 100);
    d->opacitySlider->blockSignals(false);

    d->view->setCurrentLayer(layer);
    d->lutComboBox->blockSignals(true);
    d->lutComboBox->setCurrentIndex(0);
    d->lutComboBox->blockSignals(false);
    d->view->setProperty("LookupTable", "Default");
    d->view->update();
}

void
medViewerToolBoxViewProperties::onViewClosed(void)
{
    d->dataComboBox->clear();
    d->opacity->setValue(1.0);
    d->opacitySlider->setValue(100);
    d->visible->setChecked(true);
    d->propertiesToolBoxWidget->setEnabled(false);
}

void
medViewerToolBoxViewProperties::onDataSelected(int index)
{
    if (!d->view || (index == -1))
        return;

    // this method should update toolbox's GUI w.r.t selected data settings
    // to me, it should not set data settings (only current layer)
    d->view->setCurrentLayer(index);

    // d->view->setVisibility(d->view->visibility(index), index);

    d->visible->blockSignals(true);
    d->visible->setChecked((d->view->visibility(index) == 1));
    d->visible->blockSignals(false);
    // d->view->setOpacity(d->view->opacity(index), index);

    d->opacity->blockSignals(true);
    d->opacity->setValue(d->view->opacity(index));
    d->opacitySlider->setValue((int) (d->opacity->value() * 100));
    d->opacity->blockSignals(false);
}

void
medViewerToolBoxViewProperties::onVisibilitySet(int state)
{
    if ((!d->view) || (d->dataComboBox->currentIndex() == -1))
        return;

    if (state == Qt::Checked)
        d->view->setVisibility(1, d->dataComboBox->currentIndex());
    else
        d->view->setVisibility(0, d->dataComboBox->currentIndex());
    d->view->update();
}

void
medViewerToolBoxViewProperties::onOpacitySet(double opacity)
{
    if ((!d->view) || (d->dataComboBox->currentIndex() == -1))
        return;

    d->opacitySlider->blockSignals(true);
    d->opacitySlider->setValue((int) (d->opacity->value() * 100));
    d->opacitySlider->blockSignals(false);

    d->view->setOpacity(opacity, d->dataComboBox->currentIndex());
    d->view->update();
}

void
medViewerToolBoxViewProperties::onOpacitySliderSet(int opacity)
{
    if ((!d->view) || (d->dataComboBox->currentIndex() == -1))
        return;

    d->opacity->blockSignals(true);
    double d_opacity = static_cast<double> (opacity) / 100.0;
    d->opacity->setValue(d_opacity);
    d->opacity->blockSignals(false);

    d->view->setOpacity(d_opacity, d->dataComboBox->currentIndex());
    d->view->update();
}

void
medViewerToolBoxViewProperties::onLUTChanged(int index)
{
    if ((!d->view) || (d->dataComboBox->currentIndex() == -1))
        return;

    d->view->setProperty("LookupTable", d->lutComboBox->itemText(index));
    d->view->update();
}

<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: firststart.hxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 17:49:06 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _SOCOMP_FIRSTSTART_HXX_
#define _SOCOMP_FIRSTSTART_HXX_

#ifndef _COM_SUN_STAR_LANG_XSERVICEINFO_HPP_
#include <com/sun/star/lang/XServiceInfo.hpp>
#endif
#ifndef _COM_SUN_STAR_UNO_EXCEPTION_HPP_
#include <com/sun/star/uno/Exception.hpp>
#endif
#ifndef _COM_SUN_STAR_UNO_REFERENCE_H_
#include <com/sun/star/uno/Reference.h>
#endif
#ifndef _COM_SUN_STAR_LANG_XCOMPONENT_HPP_
#include <com/sun/star/lang/XComponent.hpp>
#endif
#ifndef _COM_SUN_STAR_TASK_XJOB_HPP_
#include <com/sun/star/task/XJob.hpp>
#endif
#ifndef _CPPUHELPER_IMPLBASE4_HXX_
#include <cppuhelper/implbase4.hxx>
#endif
#ifndef _CPPUHELPER_INTERFACECONTAINER_H_
#include <cppuhelper/interfacecontainer.h>
#endif
#include <com/sun/star/task/XJobExecutor.hpp>
#include <com/sun/star/lang/XSingleServiceFactory.hpp>
#include <osl/mutex.hxx>

using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::task;

namespace desktop{

class FirstStart : public ::cppu::WeakImplHelper4< XJob, XJobExecutor, XComponent, XServiceInfo >
{

private:
    ::osl::Mutex                        m_aMutex;
    ::cppu::OInterfaceContainerHelper   m_aListeners;
    Reference< XMultiServiceFactory >   m_xServiceManager;

public:
    FirstStart( const Reference < XMultiServiceFactory >& xFactory );
    virtual ~FirstStart();

    static ::rtl::OUString                      GetImplementationName();
    static Sequence< rtl::OUString >            GetSupportedServiceNames();

    // XComponent
    virtual void SAL_CALL dispose() throw ( RuntimeException );
    virtual void SAL_CALL addEventListener( const Reference< XEventListener > & aListener) throw ( RuntimeException );
    virtual void SAL_CALL removeEventListener(const Reference< XEventListener > & aListener) throw ( RuntimeException );

    // XServiceInfo
    virtual ::rtl::OUString SAL_CALL    getImplementationName() throw ( RuntimeException );
    virtual sal_Bool SAL_CALL           supportsService( const ::rtl::OUString& rServiceName ) throw ( RuntimeException );
    virtual Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames() throw ( RuntimeException );

    //XJob
    virtual Any SAL_CALL execute(const Sequence<NamedValue>& args)throw ( RuntimeException );
    //XJobExecutor
    virtual void SAL_CALL trigger(const rtl::OUString& arg)throw ( RuntimeException );

    static const char* interfaces[];
    static const char* implementationName;
    static const char* serviceName;
    static Reference<XInterface> SAL_CALL CreateInstance(
        const Reference< XMultiServiceFactory >&);

};
}

#endif // _SOCOMP_FIRSTSTART_HXX_
<commit_msg>INTEGRATION: CWS changefileheader (1.2.614); FILE MERGED 2008/04/01 15:13:10 thb 1.2.614.3: #i85898# Stripping all external header guards 2008/04/01 10:55:01 thb 1.2.614.2: #i85898# Stripping all external header guards 2008/03/28 15:27:08 rt 1.2.614.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: firststart.hxx,v $
 * $Revision: 1.3 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef _SOCOMP_FIRSTSTART_HXX_
#define _SOCOMP_FIRSTSTART_HXX_

#include <com/sun/star/lang/XServiceInfo.hpp>
#include <com/sun/star/uno/Exception.hpp>
#include <com/sun/star/uno/Reference.h>
#include <com/sun/star/lang/XComponent.hpp>
#include <com/sun/star/task/XJob.hpp>
#include <cppuhelper/implbase4.hxx>
#include <cppuhelper/interfacecontainer.h>
#include <com/sun/star/task/XJobExecutor.hpp>
#include <com/sun/star/lang/XSingleServiceFactory.hpp>
#include <osl/mutex.hxx>

using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::task;

namespace desktop{

class FirstStart : public ::cppu::WeakImplHelper4< XJob, XJobExecutor, XComponent, XServiceInfo >
{

private:
    ::osl::Mutex                        m_aMutex;
    ::cppu::OInterfaceContainerHelper   m_aListeners;
    Reference< XMultiServiceFactory >   m_xServiceManager;

public:
    FirstStart( const Reference < XMultiServiceFactory >& xFactory );
    virtual ~FirstStart();

    static ::rtl::OUString                      GetImplementationName();
    static Sequence< rtl::OUString >            GetSupportedServiceNames();

    // XComponent
    virtual void SAL_CALL dispose() throw ( RuntimeException );
    virtual void SAL_CALL addEventListener( const Reference< XEventListener > & aListener) throw ( RuntimeException );
    virtual void SAL_CALL removeEventListener(const Reference< XEventListener > & aListener) throw ( RuntimeException );

    // XServiceInfo
    virtual ::rtl::OUString SAL_CALL    getImplementationName() throw ( RuntimeException );
    virtual sal_Bool SAL_CALL           supportsService( const ::rtl::OUString& rServiceName ) throw ( RuntimeException );
    virtual Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames() throw ( RuntimeException );

    //XJob
    virtual Any SAL_CALL execute(const Sequence<NamedValue>& args)throw ( RuntimeException );
    //XJobExecutor
    virtual void SAL_CALL trigger(const rtl::OUString& arg)throw ( RuntimeException );

    static const char* interfaces[];
    static const char* implementationName;
    static const char* serviceName;
    static Reference<XInterface> SAL_CALL CreateInstance(
        const Reference< XMultiServiceFactory >&);

};
}

#endif // _SOCOMP_FIRSTSTART_HXX_
<|endoftext|>


<commit_before>/*
  Copyright (C) 2006 by Jorrit Tyberghein
            (C) 2006 by Frank Richter

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Library General Public
  License as published by the Free Software Foundation; either
  version 2 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Library General Public License for more details.

  You should have received a copy of the GNU Library General Public
  License along with this library; if not, write to the Free
  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "cssysdef.h"

#include "csgeom/math3d.h"
#include "csgfx/renderbuffer.h"
#include "csgfx/vertexlistwalker.h"
#include "cstool/rbuflock.h"

#include "submeshes.h"
#include "genmesh.h"

CS_PLUGIN_NAMESPACE_BEGIN(Genmesh)
{
  SubMesh::LegacyTriangles::LegacyTriangles() : triangles_setup (false),
    mesh_triangle_dirty_flag (false)
  {
  }

  void SubMesh::CreateLegacyBuffer()
  {
    if (!legacyTris.triangles_setup)
    {
      if (index_buffer.IsValid())
      {
	if ((index_buffer->GetComponentType() == CS_BUFCOMP_INT)
	    || (index_buffer->GetComponentType() == CS_BUFCOMP_UNSIGNED_INT))
	{
	  size_t triNum = index_buffer->GetElementCount() / 3;
	  legacyTris.mesh_triangles.SetSize (triNum);
	  csRenderBufferLock<uint8> indexLock (index_buffer, CS_BUF_LOCK_READ);
	  memcpy (legacyTris.mesh_triangles.GetArray(),
	    indexLock.Lock(), triNum * sizeof (csTriangle));
	}
	else
	{
	  size_t indexTris = index_buffer->GetElementCount() / 3;
	  legacyTris.mesh_triangles.Empty();
	  legacyTris.mesh_triangles.SetCapacity (indexTris);
	  CS::TriangleIndicesStream<int> triangles (index_buffer,
	    CS_MESHTYPE_TRIANGLES);
	  while (triangles.HasNext())
	    legacyTris.mesh_triangles.Push (triangles.Next());
	}
      }

      legacyTris.mesh_triangle_dirty_flag = true;
      legacyTris.triangles_setup = true;
    }
  }

  void SubMesh::ClearLegacyBuffer()
  {
    if (!legacyTris.triangles_setup) return;
    legacyTris.triangles_setup = false;
    legacyTris.mesh_triangle_dirty_flag = false;
    legacyTris.mesh_triangles.DeleteAll ();
  }

  void SubMesh::UpdateFromLegacyBuffer ()
  {
    if (legacyTris.triangles_setup)
    {
      if (legacyTris.mesh_triangle_dirty_flag)
      {
	size_t rangeMin = (size_t)~0, rangeMax = 0;
	for (size_t n = 0; n < legacyTris.mesh_triangles.GetSize(); n++)
	{
	  for (int e = 0; e < 3; e++)
	  {
	    size_t index = size_t (legacyTris.mesh_triangles[n][e]);
	    if (index < rangeMin)
	      rangeMin = index;
	    else if (index > rangeMax)
	      rangeMax = index;
	  }
	}
	csRef<iRenderBuffer> newBuffer =
	  csRenderBuffer::CreateIndexRenderBuffer (
	    legacyTris.mesh_triangles.GetSize() * 3, CS_BUF_STATIC,
	    CS_BUFCOMP_UNSIGNED_INT, rangeMin,
	    rangeMax);
	newBuffer->SetData (legacyTris.mesh_triangles.GetArray());
	index_buffer = newBuffer;
	legacyTris.mesh_triangle_dirty_flag = false;
      }
    }
  }

  iRenderBuffer* SubMesh::GetIndicesB2F (const csVector3& pos, uint frameNum,
                                         const csVector3* vertices, size_t vertNum)
  {
    UpdateFromLegacyBuffer();

    if (!b2fTree)
    {
      CS::TriangleIndicesStream<int> triangles (index_buffer,
	CS_MESHTYPE_TRIANGLES);
      b2fTree = new csBSPTree;
      b2fTree->Build (triangles, vertices);
    }

    const csDirtyAccessArray<int>& triidx = b2fTree->Back2Front (pos);

    bool bufCreated;
    csRef<iRenderBuffer>& newIndexBuffer = b2fIndices.GetUnusedData (bufCreated, frameNum);
    if (bufCreated || newIndexBuffer->GetElementCount() != triidx.GetSize()*3)
    {
      newIndexBuffer = csRenderBuffer::CreateIndexRenderBuffer (triidx.GetSize()*3,
        CS_BUF_STREAM, CS_BUFCOMP_UNSIGNED_INT, 0, vertNum-1);
    }
    csRenderBufferLock<int> indices (newIndexBuffer);
    CS::TriangleIndicesStreamRandom<int> triangles (index_buffer,
      CS_MESHTYPE_TRIANGLES);
    for (size_t t = 0; t < triidx.GetSize(); t++)
    {
      const TriangleT<int> tri (triangles[triidx[t]]);
      *(indices++) = tri.a;
      *(indices++) = tri.b;
      *(indices++) = tri.c;
    }
    return newIndexBuffer;
  }

  iRenderBuffer* SubMesh::GetIndices ()
  {
    UpdateFromLegacyBuffer();
    return index_buffer;
  }

  void SubMesh::SetIndices (iRenderBuffer* indices)
  {
    ClearLegacyBuffer();
    index_buffer = indices;
    if (b2fTree)
    {
      delete b2fTree;
      b2fTree = 0;
    }
    InvalidateBoundingBox ();
  }

  template<typename T>
  void SubMesh::IterateAllVertices (iRenderBuffer* positions, T& functor)
  {
    UpdateFromLegacyBuffer();
    if (!index_buffer.IsValid()) return;

    csVertexListWalker<float, csVector3> vertices (positions);

    /* Set up a simple hash table to store which vertices have already
       been seen & handled, to avoid, to some degree, unnecessary
       bbox vertex adds. */
    const size_t maxVertexHashSize = 4093;
    const size_t indexOffs = index_buffer->GetRangeStart();
    const size_t vertexHashSize = csMin (maxVertexHashSize,
      index_buffer->GetRangeEnd() - indexOffs + 1);
    CS_ALLOC_STACK_ARRAY(size_t, seenVertices, vertexHashSize);
    for (size_t v = 0; v < vertexHashSize; v++) seenVertices[v] = (size_t)~0;

    CS::TriangleIndicesStream<size_t> triangles (index_buffer,
      CS_MESHTYPE_TRIANGLES);
    while (triangles.HasNext())
    {
      const TriangleT<size_t> tri (triangles.Next());
      for (int v = 0; v < 3; v++)
      {
        size_t vertex = tri[v];
        const size_t vertexHashIndex = (vertex-indexOffs) % vertexHashSize;
        if (seenVertices[vertexHashIndex] == vertex) continue;

        vertices.SetElement (vertex);
        const csVector3& vert = *vertices;
        functor (vert);

        seenVertices[vertexHashIndex] = vertex;
      }
    }

  }

  struct IterateBB
  {
    csBox3 bbox;

    void operator() (const csVector3& pos)
    { bbox.AddBoundingVertex (pos); }
  };

  const csBox3& SubMesh::GetObjectBoundingBox (iRenderBuffer* positions)
  {
    if (!bbox_valid)
    {
      IterateBB itbb;
      IterateAllVertices (positions, itbb);
      bbox = itbb.bbox;
      bbox_valid = true;
    }
    return bbox;
  }

  struct IterateRadius
  {
    csVector3 center;
    float sqradius;

    IterateRadius (const csVector3& center) : center (center), sqradius (0) {}
    void operator() (const csVector3& pos)
    { sqradius = csMax (sqradius, csSquaredDist::PointPoint (center, pos)); }
  };

  float SubMesh::ComputeMaxSqRadius (iRenderBuffer* positions,
                                     const csVector3& center)
  {
    IterateRadius itr (center);
    IterateAllVertices (positions, itr);
    return itr.sqradius;
  }

  void SubMesh::InvalidateBoundingBox ()
  {
    bbox_valid = false;
  }

  //-------------------------------------------------------------------------

  SubMeshesContainer::SubMeshesContainer() : changeNum (0)
  {
    defaultSubmesh.AttachNew (new SubMesh);
    subMeshes.Push (defaultSubmesh);
  }

  static int SubmeshSubmeshCompare (SubMesh* const& A,
                                    SubMesh* const& B)
  {
    const char* a = A->GetName();
    const char* b = B->GetName();
    if (a == 0) return (b == 0) ? 0 : 1;
    if (b == 0) return -1;
    return strcmp (a, b);
  }

  iGeneralMeshSubMesh* SubMeshesContainer::AddSubMesh (
    iRenderBuffer* indices, iMaterialWrapper *material, const char* name,
    uint mixmode)
  {
    if ((subMeshes.GetSize() == 1) && (subMeshes[0] == defaultSubmesh))
    {
      if(defaultSubmesh->GetMaterial() == 0)
        defaultSubmesh->SetMaterial(material);

      subMeshes.Empty();
    }

    csRef<SubMesh> subMesh;
    subMesh.AttachNew (new SubMesh ());
    subMesh->material = material;
    subMesh->MixMode = mixmode;
    subMesh->name = name;
    subMesh->SetIndices (indices);

    subMeshes.InsertSorted (subMesh, SubmeshSubmeshCompare);
    /* @@@ FIXME: Prolly do some error checking, like sanity of
     * indices */
    changeNum++;
    return subMesh;
  }

  static int SubmeshStringCompare (SubMesh* const& A, const char* const& b)
  {
    const char* a = A->GetName();
    if (a == 0) return (b == 0) ? 0 : 1;
    if (b == 0) return -1;
    return strcmp (a, b);
  }

  SubMesh* SubMeshesContainer::FindSubMesh (const char* name) const
  {
    size_t idx = subMeshes.FindSortedKey (
      csArrayCmp<SubMesh*, const char*> (name, &SubmeshStringCompare));
    if (idx == csArrayItemNotFound) return 0;
    return subMeshes[idx];
  }

  void SubMeshesContainer::DeleteSubMesh (iGeneralMeshSubMesh* mesh)
  {
    SubMesh* subMesh = static_cast<SubMesh*> (mesh);
    size_t idx = subMeshes.FindSortedKey (
      csArrayCmp<SubMesh*, SubMesh*> (subMesh, &SubmeshSubmeshCompare));
    if (idx == csArrayItemNotFound) return;
    subMeshes.DeleteIndex (idx);

    if (subMeshes.GetSize() == 0)
      subMeshes.Push (defaultSubmesh);
  }

  void SubMeshesContainer::SetMaterialWrapper(iMaterialWrapper* mat)
  {
      defaultSubmesh->SetMaterial(mat);
      if((subMeshes.GetSize() == 1) && (subMeshes[0] != defaultSubmesh))
      {
          subMeshes[0]->SetMaterial(mat);
      }
  }

  iMaterialWrapper* SubMeshesContainer::GetMaterialWrapper() const
  {
      if((subMeshes.GetSize() == 1) && (subMeshes[0] != defaultSubmesh))
      {
          return subMeshes[0]->GetMaterial();
      }

      return defaultSubmesh->GetMaterial();
  }

  //-------------------------------------------------------------------------

  csRenderBufferHolder* SubMeshProxy::GetBufferHolder (
    csRenderBufferHolder* copyFrom)
  {
    if (!renderBufferAccessor.IsValid())
      renderBufferAccessor.AttachNew (new RenderBufferAccessor (this));
    if (!bufferHolder.IsValid())
      bufferHolder.AttachNew (new csRenderBufferHolder);
    *bufferHolder = *copyFrom;
    if (parentSubMesh->legacyTris.mesh_triangle_dirty_flag)
    {
      renderBufferAccessor->wrappedHolder = copyFrom->GetAccessor();
      bufferHolder->SetAccessor (renderBufferAccessor,
	copyFrom->GetAccessorMask() | CS_BUFFER_INDEX_MASK);
    }
    else
    {
      renderBufferAccessor->wrappedHolder.Invalidate();
      bufferHolder->SetAccessor (copyFrom->GetAccessor(),
	copyFrom->GetAccessorMask() & ~CS_BUFFER_INDEX_MASK);
      bufferHolder->SetRenderBuffer (CS_BUFFER_INDEX,
	parentSubMesh->GetIndices());
    }
    return bufferHolder;
  }

  //-------------------------------------------------------------------------

  void SubMeshProxy::RenderBufferAccessor::PreGetBuffer (
    csRenderBufferHolder* holder, csRenderBufferName buffer)
  {
    if ((buffer == CS_BUFFER_INDEX) && (parent.IsValid()))
      holder->SetRenderBuffer (CS_BUFFER_INDEX, parent->GetIndices());
    else
      wrappedHolder->PreGetBuffer (holder, buffer);
  }

  //-------------------------------------------------------------------------

  SubMeshProxiesContainer::SubMeshProxiesContainer ()
  {
    defaultSubmesh.AttachNew (new SubMeshProxy);
    subMeshes.Push (defaultSubmesh);
  }

  SubMeshProxiesContainer::SubMeshProxiesContainer (SubMeshProxy* dflt)
   : defaultSubmesh (dflt)
  {
  }

  static int SubmeshProxySubmeshProxyCompare (SubMeshProxy* const& A,
                                              SubMeshProxy* const& B)
  {
    const char* a = A->GetName();
    const char* b = B->GetName();
    if (a == 0) return (b == 0) ? 0 : 1;
    if (b == 0) return -1;
    return strcmp (a, b);
  }

  void SubMeshProxiesContainer::AddSubMesh (SubMeshProxy* subMesh)
  {
    if ((subMeshes.GetSize() == 1) && (subMeshes[0] == defaultSubmesh))
    {
      if(defaultSubmesh->GetMaterial() == 0)
        defaultSubmesh->SetMaterial(subMesh->GetMaterial());

      subMeshes.Empty();
    }

    subMeshes.InsertSorted (subMesh, SubmeshProxySubmeshProxyCompare);
  }

  static int SubmeshProxyStringCompare (SubMeshProxy* const& A, const char* const& b)
  {
    const char* a = A->GetName();
    if (a == 0) return (b == 0) ? 0 : 1;
    if (b == 0) return -1;
    return strcmp (a, b);
  }

  SubMeshProxy* SubMeshProxiesContainer::FindSubMesh (const char* name) const
  {
    size_t idx = subMeshes.FindSortedKey (
      csArrayCmp<SubMeshProxy*, const char*> (name, &SubmeshProxyStringCompare));
    if (idx == csArrayItemNotFound) return 0;
    return subMeshes[idx];
  }

  void SubMeshProxiesContainer::SetMaterialWrapper(iMaterialWrapper* mat)
  {
      defaultSubmesh->SetMaterial(mat);
      if((subMeshes.GetSize() == 1) && (subMeshes[0] != defaultSubmesh))
      {
          subMeshes[0]->SetMaterial(mat);
      }
  }

  iMaterialWrapper* SubMeshProxiesContainer::GetMaterialWrapper() const
  {
      if((subMeshes.GetSize() == 1) && (subMeshes[0] != defaultSubmesh))
      {
          return subMeshes[0]->GetMaterial();
      }

      return defaultSubmesh->GetMaterial();
  }

  //-------------------------------------------------------------------------

  void SubMeshesTriMesh::CacheTriangles ()
  {
    if (triChangeNum == subMeshes.GetChangeNum()) return;

    triangleCache.Empty();
    for (size_t s = 0; s < subMeshes.GetSubMeshCount(); s++)
    {
      SubMesh* subMesh = subMeshes.GetSubMesh (s);
      iRenderBuffer* buffer = subMesh->GetIndices();
      size_t offs = triangleCache.GetSize();
      size_t bufferTris = buffer->GetElementCount() / 3;
      triangleCache.SetSize (offs + bufferTris);
      void* tris = buffer->Lock (CS_BUF_LOCK_READ);
      memcpy (triangleCache.GetArray() + offs, tris,
        bufferTris * sizeof (csTriangle));
      buffer->Release();
    }
    triangleCache.ShrinkBestFit();

    triChangeNum = subMeshes.GetChangeNum();
  }

  size_t SubMeshesTriMesh::GetVertexCount ()
  {
    if (!factory) return 0;
    return factory->GetVertexCount ();
  }
  csVector3* SubMeshesTriMesh::GetVertices ()
  {
    if (!factory) return 0;
    return factory->GetVertices ();
  }
  size_t SubMeshesTriMesh::GetTriangleCount ()
  {
    if (!factory) return 0;
    CacheTriangles ();
    return triangleCache.GetSize ();
  }
  csTriangle* SubMeshesTriMesh::GetTriangles ()
  {
    if (!factory) return 0;
    CacheTriangles ();
    return triangleCache.GetArray ();
  }

}
CS_PLUGIN_NAMESPACE_END(Genmesh)
<commit_msg>Patch from eventhorizon5 fixing the deletion of submeshes. Fixes ticket #882<commit_after>/*
  Copyright (C) 2006 by Jorrit Tyberghein
            (C) 2006 by Frank Richter

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Library General Public
  License as published by the Free Software Foundation; either
  version 2 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Library General Public License for more details.

  You should have received a copy of the GNU Library General Public
  License along with this library; if not, write to the Free
  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "cssysdef.h"

#include "csgeom/math3d.h"
#include "csgfx/renderbuffer.h"
#include "csgfx/vertexlistwalker.h"
#include "cstool/rbuflock.h"

#include "submeshes.h"
#include "genmesh.h"

CS_PLUGIN_NAMESPACE_BEGIN(Genmesh)
{
  SubMesh::LegacyTriangles::LegacyTriangles() : triangles_setup (false),
    mesh_triangle_dirty_flag (false)
  {
  }

  void SubMesh::CreateLegacyBuffer()
  {
    if (!legacyTris.triangles_setup)
    {
      if (index_buffer.IsValid())
      {
	if ((index_buffer->GetComponentType() == CS_BUFCOMP_INT)
	    || (index_buffer->GetComponentType() == CS_BUFCOMP_UNSIGNED_INT))
	{
	  size_t triNum = index_buffer->GetElementCount() / 3;
	  legacyTris.mesh_triangles.SetSize (triNum);
	  csRenderBufferLock<uint8> indexLock (index_buffer, CS_BUF_LOCK_READ);
	  memcpy (legacyTris.mesh_triangles.GetArray(),
	    indexLock.Lock(), triNum * sizeof (csTriangle));
	}
	else
	{
	  size_t indexTris = index_buffer->GetElementCount() / 3;
	  legacyTris.mesh_triangles.Empty();
	  legacyTris.mesh_triangles.SetCapacity (indexTris);
	  CS::TriangleIndicesStream<int> triangles (index_buffer,
	    CS_MESHTYPE_TRIANGLES);
	  while (triangles.HasNext())
	    legacyTris.mesh_triangles.Push (triangles.Next());
	}
      }

      legacyTris.mesh_triangle_dirty_flag = true;
      legacyTris.triangles_setup = true;
    }
  }

  void SubMesh::ClearLegacyBuffer()
  {
    if (!legacyTris.triangles_setup) return;
    legacyTris.triangles_setup = false;
    legacyTris.mesh_triangle_dirty_flag = false;
    legacyTris.mesh_triangles.DeleteAll ();
  }

  void SubMesh::UpdateFromLegacyBuffer ()
  {
    if (legacyTris.triangles_setup)
    {
      if (legacyTris.mesh_triangle_dirty_flag)
      {
	size_t rangeMin = (size_t)~0, rangeMax = 0;
	for (size_t n = 0; n < legacyTris.mesh_triangles.GetSize(); n++)
	{
	  for (int e = 0; e < 3; e++)
	  {
	    size_t index = size_t (legacyTris.mesh_triangles[n][e]);
	    if (index < rangeMin)
	      rangeMin = index;
	    else if (index > rangeMax)
	      rangeMax = index;
	  }
	}
	csRef<iRenderBuffer> newBuffer =
	  csRenderBuffer::CreateIndexRenderBuffer (
	    legacyTris.mesh_triangles.GetSize() * 3, CS_BUF_STATIC,
	    CS_BUFCOMP_UNSIGNED_INT, rangeMin,
	    rangeMax);
	newBuffer->SetData (legacyTris.mesh_triangles.GetArray());
	index_buffer = newBuffer;
	legacyTris.mesh_triangle_dirty_flag = false;
      }
    }
  }

  iRenderBuffer* SubMesh::GetIndicesB2F (const csVector3& pos, uint frameNum,
                                         const csVector3* vertices, size_t vertNum)
  {
    UpdateFromLegacyBuffer();

    if (!b2fTree)
    {
      CS::TriangleIndicesStream<int> triangles (index_buffer,
	CS_MESHTYPE_TRIANGLES);
      b2fTree = new csBSPTree;
      b2fTree->Build (triangles, vertices);
    }

    const csDirtyAccessArray<int>& triidx = b2fTree->Back2Front (pos);

    bool bufCreated;
    csRef<iRenderBuffer>& newIndexBuffer = b2fIndices.GetUnusedData (bufCreated, frameNum);
    if (bufCreated || newIndexBuffer->GetElementCount() != triidx.GetSize()*3)
    {
      newIndexBuffer = csRenderBuffer::CreateIndexRenderBuffer (triidx.GetSize()*3,
        CS_BUF_STREAM, CS_BUFCOMP_UNSIGNED_INT, 0, vertNum-1);
    }
    csRenderBufferLock<int> indices (newIndexBuffer);
    CS::TriangleIndicesStreamRandom<int> triangles (index_buffer,
      CS_MESHTYPE_TRIANGLES);
    for (size_t t = 0; t < triidx.GetSize(); t++)
    {
      const TriangleT<int> tri (triangles[triidx[t]]);
      *(indices++) = tri.a;
      *(indices++) = tri.b;
      *(indices++) = tri.c;
    }
    return newIndexBuffer;
  }

  iRenderBuffer* SubMesh::GetIndices ()
  {
    UpdateFromLegacyBuffer();
    return index_buffer;
  }

  void SubMesh::SetIndices (iRenderBuffer* indices)
  {
    ClearLegacyBuffer();
    index_buffer = indices;
    if (b2fTree)
    {
      delete b2fTree;
      b2fTree = 0;
    }
    InvalidateBoundingBox ();
  }

  template<typename T>
  void SubMesh::IterateAllVertices (iRenderBuffer* positions, T& functor)
  {
    UpdateFromLegacyBuffer();
    if (!index_buffer.IsValid()) return;

    csVertexListWalker<float, csVector3> vertices (positions);

    /* Set up a simple hash table to store which vertices have already
       been seen & handled, to avoid, to some degree, unnecessary
       bbox vertex adds. */
    const size_t maxVertexHashSize = 4093;
    const size_t indexOffs = index_buffer->GetRangeStart();
    const size_t vertexHashSize = csMin (maxVertexHashSize,
      index_buffer->GetRangeEnd() - indexOffs + 1);
    CS_ALLOC_STACK_ARRAY(size_t, seenVertices, vertexHashSize);
    for (size_t v = 0; v < vertexHashSize; v++) seenVertices[v] = (size_t)~0;

    CS::TriangleIndicesStream<size_t> triangles (index_buffer,
      CS_MESHTYPE_TRIANGLES);
    while (triangles.HasNext())
    {
      const TriangleT<size_t> tri (triangles.Next());
      for (int v = 0; v < 3; v++)
      {
        size_t vertex = tri[v];
        const size_t vertexHashIndex = (vertex-indexOffs) % vertexHashSize;
        if (seenVertices[vertexHashIndex] == vertex) continue;

        vertices.SetElement (vertex);
        const csVector3& vert = *vertices;
        functor (vert);

        seenVertices[vertexHashIndex] = vertex;
      }
    }

  }

  struct IterateBB
  {
    csBox3 bbox;

    void operator() (const csVector3& pos)
    { bbox.AddBoundingVertex (pos); }
  };

  const csBox3& SubMesh::GetObjectBoundingBox (iRenderBuffer* positions)
  {
    if (!bbox_valid)
    {
      IterateBB itbb;
      IterateAllVertices (positions, itbb);
      bbox = itbb.bbox;
      bbox_valid = true;
    }
    return bbox;
  }

  struct IterateRadius
  {
    csVector3 center;
    float sqradius;

    IterateRadius (const csVector3& center) : center (center), sqradius (0) {}
    void operator() (const csVector3& pos)
    { sqradius = csMax (sqradius, csSquaredDist::PointPoint (center, pos)); }
  };

  float SubMesh::ComputeMaxSqRadius (iRenderBuffer* positions,
                                     const csVector3& center)
  {
    IterateRadius itr (center);
    IterateAllVertices (positions, itr);
    return itr.sqradius;
  }

  void SubMesh::InvalidateBoundingBox ()
  {
    bbox_valid = false;
  }

  //-------------------------------------------------------------------------

  SubMeshesContainer::SubMeshesContainer() : changeNum (0)
  {
    defaultSubmesh.AttachNew (new SubMesh);
    subMeshes.Push (defaultSubmesh);
  }

  static int SubmeshSubmeshCompare (SubMesh* const& A,
                                    SubMesh* const& B)
  {
    if (A < B)
    	return -1;
    if (A > B)
    	return 1;
    return 0;
  }

  iGeneralMeshSubMesh* SubMeshesContainer::AddSubMesh (
    iRenderBuffer* indices, iMaterialWrapper *material, const char* name,
    uint mixmode)
  {
    if ((subMeshes.GetSize() == 1) && (subMeshes[0] == defaultSubmesh))
    {
      if(defaultSubmesh->GetMaterial() == 0)
        defaultSubmesh->SetMaterial(material);

      subMeshes.Empty();
    }

    csRef<SubMesh> subMesh;
    subMesh.AttachNew (new SubMesh ());
    subMesh->material = material;
    subMesh->MixMode = mixmode;
    subMesh->name = name;
    subMesh->SetIndices (indices);

    subMeshes.InsertSorted (subMesh, SubmeshSubmeshCompare);
    /* @@@ FIXME: Prolly do some error checking, like sanity of
     * indices */
    changeNum++;
    return subMesh;
  }

  static int SubmeshStringCompare (SubMesh* const& A, const char* const& b)
  {
    const char* a = A->GetName();
    if (a == 0) return (b == 0) ? 0 : 1;
    if (b == 0) return -1;
    return strcmp (a, b);
  }

  SubMesh* SubMeshesContainer::FindSubMesh (const char* name) const
  {
    size_t idx = subMeshes.FindSortedKey (
      csArrayCmp<SubMesh*, const char*> (name, &SubmeshStringCompare));
    if (idx == csArrayItemNotFound) return 0;
    return subMeshes[idx];
  }

  void SubMeshesContainer::DeleteSubMesh (iGeneralMeshSubMesh* mesh)
  {
    SubMesh* subMesh = static_cast<SubMesh*> (mesh);
    size_t idx = subMeshes.FindSortedKey (
      csArrayCmp<SubMesh*, SubMesh*> (subMesh, &SubmeshSubmeshCompare));
    if (idx == csArrayItemNotFound) return;
    subMeshes.DeleteIndex (idx);
    changeNum++;

    if (subMeshes.GetSize() == 0)
      subMeshes.Push (defaultSubmesh);
  }

  void SubMeshesContainer::SetMaterialWrapper(iMaterialWrapper* mat)
  {
      defaultSubmesh->SetMaterial(mat);
      if((subMeshes.GetSize() == 1) && (subMeshes[0] != defaultSubmesh))
      {
          subMeshes[0]->SetMaterial(mat);
      }
  }

  iMaterialWrapper* SubMeshesContainer::GetMaterialWrapper() const
  {
      if((subMeshes.GetSize() == 1) && (subMeshes[0] != defaultSubmesh))
      {
          return subMeshes[0]->GetMaterial();
      }

      return defaultSubmesh->GetMaterial();
  }

  //-------------------------------------------------------------------------

  csRenderBufferHolder* SubMeshProxy::GetBufferHolder (
    csRenderBufferHolder* copyFrom)
  {
    if (!renderBufferAccessor.IsValid())
      renderBufferAccessor.AttachNew (new RenderBufferAccessor (this));
    if (!bufferHolder.IsValid())
      bufferHolder.AttachNew (new csRenderBufferHolder);
    *bufferHolder = *copyFrom;
    if (parentSubMesh->legacyTris.mesh_triangle_dirty_flag)
    {
      renderBufferAccessor->wrappedHolder = copyFrom->GetAccessor();
      bufferHolder->SetAccessor (renderBufferAccessor,
	copyFrom->GetAccessorMask() | CS_BUFFER_INDEX_MASK);
    }
    else
    {
      renderBufferAccessor->wrappedHolder.Invalidate();
      bufferHolder->SetAccessor (copyFrom->GetAccessor(),
	copyFrom->GetAccessorMask() & ~CS_BUFFER_INDEX_MASK);
      bufferHolder->SetRenderBuffer (CS_BUFFER_INDEX,
	parentSubMesh->GetIndices());
    }
    return bufferHolder;
  }

  //-------------------------------------------------------------------------

  void SubMeshProxy::RenderBufferAccessor::PreGetBuffer (
    csRenderBufferHolder* holder, csRenderBufferName buffer)
  {
    if ((buffer == CS_BUFFER_INDEX) && (parent.IsValid()))
      holder->SetRenderBuffer (CS_BUFFER_INDEX, parent->GetIndices());
    else
      wrappedHolder->PreGetBuffer (holder, buffer);
  }

  //-------------------------------------------------------------------------

  SubMeshProxiesContainer::SubMeshProxiesContainer ()
  {
    defaultSubmesh.AttachNew (new SubMeshProxy);
    subMeshes.Push (defaultSubmesh);
  }

  SubMeshProxiesContainer::SubMeshProxiesContainer (SubMeshProxy* dflt)
   : defaultSubmesh (dflt)
  {
  }

  static int SubmeshProxySubmeshProxyCompare (SubMeshProxy* const& A,
                                              SubMeshProxy* const& B)
  {
    const char* a = A->GetName();
    const char* b = B->GetName();
    if (a == 0) return (b == 0) ? 0 : 1;
    if (b == 0) return -1;
    return strcmp (a, b);
  }

  void SubMeshProxiesContainer::AddSubMesh (SubMeshProxy* subMesh)
  {
    if ((subMeshes.GetSize() == 1) && (subMeshes[0] == defaultSubmesh))
    {
      if(defaultSubmesh->GetMaterial() == 0)
        defaultSubmesh->SetMaterial(subMesh->GetMaterial());

      subMeshes.Empty();
    }

    subMeshes.InsertSorted (subMesh, SubmeshProxySubmeshProxyCompare);
  }

  static int SubmeshProxyStringCompare (SubMeshProxy* const& A, const char* const& b)
  {
    const char* a = A->GetName();
    if (a == 0) return (b == 0) ? 0 : 1;
    if (b == 0) return -1;
    return strcmp (a, b);
  }

  SubMeshProxy* SubMeshProxiesContainer::FindSubMesh (const char* name) const
  {
    size_t idx = subMeshes.FindSortedKey (
      csArrayCmp<SubMeshProxy*, const char*> (name, &SubmeshProxyStringCompare));
    if (idx == csArrayItemNotFound) return 0;
    return subMeshes[idx];
  }

  void SubMeshProxiesContainer::SetMaterialWrapper(iMaterialWrapper* mat)
  {
      defaultSubmesh->SetMaterial(mat);
      if((subMeshes.GetSize() == 1) && (subMeshes[0] != defaultSubmesh))
      {
          subMeshes[0]->SetMaterial(mat);
      }
  }

  iMaterialWrapper* SubMeshProxiesContainer::GetMaterialWrapper() const
  {
      if((subMeshes.GetSize() == 1) && (subMeshes[0] != defaultSubmesh))
      {
          return subMeshes[0]->GetMaterial();
      }

      return defaultSubmesh->GetMaterial();
  }

  //-------------------------------------------------------------------------

  void SubMeshesTriMesh::CacheTriangles ()
  {
    if (triChangeNum == subMeshes.GetChangeNum()) return;

    triangleCache.Empty();
    for (size_t s = 0; s < subMeshes.GetSubMeshCount(); s++)
    {
      SubMesh* subMesh = subMeshes.GetSubMesh (s);
      iRenderBuffer* buffer = subMesh->GetIndices();
      size_t offs = triangleCache.GetSize();
      size_t bufferTris = buffer->GetElementCount() / 3;
      triangleCache.SetSize (offs + bufferTris);
      void* tris = buffer->Lock (CS_BUF_LOCK_READ);
      memcpy (triangleCache.GetArray() + offs, tris,
        bufferTris * sizeof (csTriangle));
      buffer->Release();
    }
    triangleCache.ShrinkBestFit();

    triChangeNum = subMeshes.GetChangeNum();
  }

  size_t SubMeshesTriMesh::GetVertexCount ()
  {
    if (!factory) return 0;
    return factory->GetVertexCount ();
  }
  csVector3* SubMeshesTriMesh::GetVertices ()
  {
    if (!factory) return 0;
    return factory->GetVertices ();
  }
  size_t SubMeshesTriMesh::GetTriangleCount ()
  {
    if (!factory) return 0;
    CacheTriangles ();
    return triangleCache.GetSize ();
  }
  csTriangle* SubMeshesTriMesh::GetTriangles ()
  {
    if (!factory) return 0;
    CacheTriangles ();
    return triangleCache.GetArray ();
  }

}
CS_PLUGIN_NAMESPACE_END(Genmesh)
<|endoftext|>