<commit_before>#include "config.h"
#include "vm.hpp"
#include "on_stack.hpp"
#include "objectmemory.hpp"

#include "builtin/array.hpp"
#include "builtin/class.hpp"
#include "builtin/module.hpp"
#include "builtin/thread.hpp"

#include "capi/handle.hpp"

#include "gc/finalize.hpp"

namespace rubinius {
  FinalizerHandler::iterator::iterator(FinalizerHandler* fh)
    : handler_(fh)
    , current_list_(NULL)
  {
    if(handler_->live_list_->empty()) {
      if(handler_->lists_->empty()) {
        current_ = handler_->live_list_->begin();
        end_ = handler_->live_list_->end();
        return;
      } else {
        current_list_ = handler_->lists_->front();
      }
    } else {
      current_list_ = handler_->live_list_;
    }

    current_ = current_list_->begin();

    if(handler_->lists_->empty()) {
      end_ = current_list_->end();
    } else {
      lists_iterator_ = handler_->lists_->begin();
      end_ = handler_->lists_->back()->end();
    }
  }

  void FinalizerHandler::iterator::next(bool live) {
    if(current_list_ == handler_->live_list_) {
      if(!live) current_->queued();

      if(++current_ == current_list_->end()) {
        if(!handler_->lists_->empty()) {
          current_list_ = *lists_iterator_;
          current_ = current_list_->begin();
        }
      }
    } else {
      if(++current_ == end_) {
        return;
      } else if(current_ == current_list_->end()) {
        if(++lists_iterator_ != handler_->lists_->end()) {
          current_list_ = *lists_iterator_;
          current_ = current_list_->begin();
        }
      }
    }
  }

  bool FinalizerHandler::iterator::end() {
    return current_ == end_;
  }

  Object* finalizer_handler_tramp(STATE) {
    state->shared().finalizer_handler()->perform(state);
    return cNil;
  }

  FinalizerHandler::FinalizerHandler(STATE)
    : AuxiliaryThread()
    , shared_(state->shared())
    , target_(state->vm())
    , self_(NULL)
    , thread_(state)
    , lists_(NULL)
    , live_list_(NULL)
    , process_list_(NULL)
    , iterator_(NULL)
    , process_item_kind_(eRuby)
    , exit_(false)
    , finishing_(false)
  {
    shared_.auxiliary_threads()->register_thread(this);
    shared_.set_finalizer_handler(this);

    lists_ = new FinalizeObjectsList();
    live_list_ = new FinalizeObjects();

    live_guard_.init();
    worker_lock_.init();
    worker_cond_.init();
    supervisor_lock_.init();
    supervisor_cond_.init();
  }

  FinalizerHandler::~FinalizerHandler() {
    shared_.auxiliary_threads()->unregister_thread(this);

    if(iterator_) delete iterator_;
    if(live_list_) delete live_list_;

    for(FinalizeObjectsList::iterator i = lists_->begin(); i != lists_->end(); ++i) {
      delete *i;
    }

    if(lists_) delete lists_;
  }

  void FinalizerHandler::start_thread(STATE) {
    SYNC(state);
    if(self_) return;
    utilities::thread::Mutex::LockGuard lg(worker_lock_);
    self_ = state->shared().new_vm();
    exit_ = false;
    thread_.set(Thread::create(state, self_, G(thread), finalizer_handler_tramp, false, true));
    run(state);
  }

  void FinalizerHandler::stop_thread(STATE) {
    SYNC(state);
    if(!self_) return;

    pthread_t os = self_->os_thread();
    {
      utilities::thread::Mutex::LockGuard lg(worker_lock_);
      // Thread might have already been stopped
      exit_ = true;
      worker_signal();
    }

    void* return_value;
    pthread_join(os, &return_value);
    self_ = NULL;
  }

  void FinalizerHandler::shutdown(STATE) {
    // We do nothing now because we have to finish processing all remaining
    // live objects once everything shuts down.
  }

  void FinalizerHandler::before_exec(STATE) {
    stop_thread(state);
  }

  void FinalizerHandler::after_exec(STATE) {
    start_thread(state);
  }

  void FinalizerHandler::before_fork(STATE) {
    stop_thread(state);
  }

  void FinalizerHandler::after_fork_parent(STATE) {
    start_thread(state);
  }

  void FinalizerHandler::after_fork_child(STATE) {
    live_guard_.init();
    worker_lock_.init();
    worker_cond_.init();
    supervisor_lock_.init();
    supervisor_cond_.init();

    start_thread(state);
  }

  void FinalizerHandler::run(STATE) {
    int error = thread_.get()->fork_attached(state);
    if(error) rubinius::bug("Unable to start finalizer handler thread");
  }

  void FinalizerHandler::perform(STATE) {
    GCTokenImpl gct;
    utilities::thread::Thread::set_os_name("rbx.finalizer");

    state->vm()->thread->hard_unlock(state, gct);

    while(!exit_) {
      if(!process_list_) first_process_item();

      if(!process_list_) {
        utilities::thread::Mutex::LockGuard lg(worker_lock_);

        if(finishing_) supervisor_signal();

        // exit_ might have been set in the mean while after
        // we grabbed the worker_lock
        if(!exit_) {
          GCIndependent indy(state);
          worker_wait();
        }

        continue;
      }

      finalize(state);
      next_process_item();
    }
  }

  void FinalizerHandler::finalize(STATE) {
    state->vm()->set_call_frame(0);

    switch(process_item_kind_) {
    case eRuby: {
      CallFrame* call_frame = 0;

      if(process_item_->ruby_finalizer) {
        // Rubinius specific code. If the finalizer is cTrue, then send the
        // object the __finalize__ message.
        if(process_item_->ruby_finalizer == cTrue) {
          process_item_->object->send(state, call_frame, state->symbol("__finalize__"));
        } else {
          Array* ary = Array::create(state, 1);
          ary->set(state, 0, process_item_->object->id(state));
          process_item_->ruby_finalizer->send(state, call_frame, G(sym_call), ary);
        }
      }

      process_item_->status = FinalizeObject::eRubyFinalized;
      break;
    }
    case eNative:
      if(process_item_->finalizer) {
        (*process_item_->finalizer)(state, process_item_->object);
      }
      process_item_->status = FinalizeObject::eNativeFinalized;
      break;
    case eRelease:
      // Unhook any handle used by fi->object so that we don't accidentally
      // try and mark it later (after we've finalized it)
      if(capi::Handle* handle = process_item_->object->handle(state)) {
        handle->forget_object();
        process_item_->object->clear_handle(state);
      }

      // If the object was remembered, unremember it.
      if(process_item_->object->remembered_p()) {
        state->memory()->unremember_object(process_item_->object);
      }

      process_item_->status = FinalizeObject::eReleased;

      break;
    }
  }

  void FinalizerHandler::first_process_item() {
    if(!process_list_ && !lists_->empty()) {
      process_list_ = lists_->back();
      process_item_ = process_list_->begin();
    }
  }

  void FinalizerHandler::next_process_item() {
    if(++process_item_ == process_list_->end()) {
      switch(process_item_kind_) {
      case eRuby:
        process_item_ = process_list_->begin();
        process_item_kind_ = eNative;
        break;
      case eNative:
        process_item_ = process_list_->begin();
        process_item_kind_ = eRelease;
        break;
      case eRelease:
        delete process_list_;
        process_list_ = NULL;
        process_item_kind_ = eRuby;
        lists_->pop_back();
        break;
      }
    }
  }

  void FinalizerHandler::finish(STATE, GCToken gct) {
    if(!self_) rubinius::bug("FinalizerHandler worker thread dead during halt");

    finishing_ = true;

    while(true) {
      {
        StopTheWorld stw(state, gct, 0);

        if(!process_list_) {
          if(live_list_->empty() && lists_->empty()) break;

          // Everything is garbage when halting so keep adding live objects to
          // finalize queue until done.
          if(!live_list_->empty()) {
            for(FinalizeObjects::iterator i = live_list_->begin();
                i != live_list_->end();
                ++i)
            {
              i->queued();
            }

            queue_objects();
          }

          first_process_item();
          if(!process_list_) break;
        }
      }

      worker_signal();

      {
        utilities::thread::Mutex::LockGuard lg(supervisor_lock_);

        state->vm()->set_call_frame(0);
        GCIndependent indy(state);
        if(process_list_) supervisor_wait();
      }
    }

    if(!lists_->empty() || !live_list_->empty() || process_list_ != NULL)
      rubinius::bug("FinalizerHandler exiting with pending finalizers");

    stop_thread(state);
  }

  void FinalizerHandler::record(Object* obj, FinalizerFunction func) {
    utilities::thread::Mutex::LockGuard lg(live_guard_);

    FinalizeObject fi;
    fi.object = obj;
    fi.status = FinalizeObject::eLive;
    fi.finalizer = func;

    // Makes a copy of fi.
    live_list_->push_front(fi);
  }

  void FinalizerHandler::set_ruby_finalizer(Object* obj, Object* finalizer) {
    utilities::thread::Mutex::LockGuard lg(live_guard_);

    // Ignore Ruby finalizers created when finishing running finalizers.
    if(finishing_) return;

    // Check if the object is already in the finalizer list.
    for(FinalizeObjects::iterator i = live_list_->begin();
        i != live_list_->end();
        ++i)
    {
      if(i->object == obj) {
        if(finalizer->nil_p()) {
          live_list_->erase(i);
        } else {
          i->ruby_finalizer = finalizer;
        }
        return;
      }
    }

    // Adding a nil finalizer is only used to delete an existing finalizer,
    // which we apparently don't have if we get here.
    if(finalizer->nil_p()) {
      return;
    }

    // Ok, create it.

    FinalizeObject fi;
    fi.object = obj;
    fi.status = FinalizeObject::eLive;

    // Rubinius specific API. If the finalizer is the object, we're going to send
    // the object __finalize__. We mark that the user wants this by putting cTrue
    // as the ruby_finalizer.
    if(obj == finalizer) {
      fi.ruby_finalizer = cTrue;
    } else {
      fi.ruby_finalizer = finalizer;
    }

    // Makes a copy of fi.
    live_list_->push_front(fi);
  }

  void FinalizerHandler::queue_objects() {
    FinalizeObjects* dead_list = new FinalizeObjects();

    for(FinalizeObjects::iterator i = live_list_->begin();
        i != live_list_->end();
        /* advance is handled in the loop */)
    {
      if(i->queued_p()) {
        dead_list->push_front(*i);
        i = live_list_->erase(i);
      } else {
        ++i;
      }
    }

    if(!dead_list->empty()) {
      lists_->push_front(dead_list);
    } else {
      delete dead_list;
    }
  }

  void FinalizerHandler::start_collection(STATE) {
    if(process_item_kind_ == eRelease) {
      while(process_list_) {
        finalize(state);
        next_process_item();
      }
    }
  }

  void FinalizerHandler::finish_collection(STATE) {
    queue_objects();

    if(iterator_) {
      delete iterator_;
      iterator_ = NULL;
    }

    worker_signal();
  }

  void FinalizerHandler::supervisor_signal() {
    supervisor_cond_.signal();
  }

  void FinalizerHandler::supervisor_wait() {
    supervisor_cond_.wait(supervisor_lock_);
  }

  void FinalizerHandler::worker_signal() {
    worker_cond_.signal();
  }

  void FinalizerHandler::worker_wait() {
    worker_cond_.wait(worker_lock_);
  }

  FinalizerHandler::iterator& FinalizerHandler::begin() {
    if(iterator_) delete iterator_;
    iterator_ = new iterator(this);
    return *iterator_;
  }
}
<commit_msg>There may be no finalizers to process at halt.<commit_after>#include "config.h"
#include "vm.hpp"
#include "on_stack.hpp"
#include "objectmemory.hpp"

#include "builtin/array.hpp"
#include "builtin/class.hpp"
#include "builtin/module.hpp"
#include "builtin/thread.hpp"

#include "capi/handle.hpp"

#include "gc/finalize.hpp"

namespace rubinius {
  FinalizerHandler::iterator::iterator(FinalizerHandler* fh)
    : handler_(fh)
    , current_list_(NULL)
  {
    if(handler_->live_list_->empty()) {
      if(handler_->lists_->empty()) {
        current_ = handler_->live_list_->begin();
        end_ = handler_->live_list_->end();
        return;
      } else {
        current_list_ = handler_->lists_->front();
      }
    } else {
      current_list_ = handler_->live_list_;
    }

    current_ = current_list_->begin();

    if(handler_->lists_->empty()) {
      end_ = current_list_->end();
    } else {
      lists_iterator_ = handler_->lists_->begin();
      end_ = handler_->lists_->back()->end();
    }
  }

  void FinalizerHandler::iterator::next(bool live) {
    if(current_list_ == handler_->live_list_) {
      if(!live) current_->queued();

      if(++current_ == current_list_->end()) {
        if(!handler_->lists_->empty()) {
          current_list_ = *lists_iterator_;
          current_ = current_list_->begin();
        }
      }
    } else {
      if(++current_ == end_) {
        return;
      } else if(current_ == current_list_->end()) {
        if(++lists_iterator_ != handler_->lists_->end()) {
          current_list_ = *lists_iterator_;
          current_ = current_list_->begin();
        }
      }
    }
  }

  bool FinalizerHandler::iterator::end() {
    return current_ == end_;
  }

  Object* finalizer_handler_tramp(STATE) {
    state->shared().finalizer_handler()->perform(state);
    return cNil;
  }

  FinalizerHandler::FinalizerHandler(STATE)
    : AuxiliaryThread()
    , shared_(state->shared())
    , target_(state->vm())
    , self_(NULL)
    , thread_(state)
    , lists_(NULL)
    , live_list_(NULL)
    , process_list_(NULL)
    , iterator_(NULL)
    , process_item_kind_(eRuby)
    , exit_(false)
    , finishing_(false)
  {
    shared_.auxiliary_threads()->register_thread(this);
    shared_.set_finalizer_handler(this);

    lists_ = new FinalizeObjectsList();
    live_list_ = new FinalizeObjects();

    live_guard_.init();
    worker_lock_.init();
    worker_cond_.init();
    supervisor_lock_.init();
    supervisor_cond_.init();
  }

  FinalizerHandler::~FinalizerHandler() {
    shared_.auxiliary_threads()->unregister_thread(this);

    if(iterator_) delete iterator_;
    if(live_list_) delete live_list_;

    for(FinalizeObjectsList::iterator i = lists_->begin(); i != lists_->end(); ++i) {
      delete *i;
    }

    if(lists_) delete lists_;
  }

  void FinalizerHandler::start_thread(STATE) {
    SYNC(state);
    if(self_) return;
    utilities::thread::Mutex::LockGuard lg(worker_lock_);
    self_ = state->shared().new_vm();
    exit_ = false;
    thread_.set(Thread::create(state, self_, G(thread), finalizer_handler_tramp, false, true));
    run(state);
  }

  void FinalizerHandler::stop_thread(STATE) {
    SYNC(state);
    if(!self_) return;

    pthread_t os = self_->os_thread();
    {
      utilities::thread::Mutex::LockGuard lg(worker_lock_);
      // Thread might have already been stopped
      exit_ = true;
      worker_signal();
    }

    void* return_value;
    pthread_join(os, &return_value);
    self_ = NULL;
  }

  void FinalizerHandler::shutdown(STATE) {
    // We do nothing now because we have to finish processing all remaining
    // live objects once everything shuts down.
  }

  void FinalizerHandler::before_exec(STATE) {
    stop_thread(state);
  }

  void FinalizerHandler::after_exec(STATE) {
    start_thread(state);
  }

  void FinalizerHandler::before_fork(STATE) {
    stop_thread(state);
  }

  void FinalizerHandler::after_fork_parent(STATE) {
    start_thread(state);
  }

  void FinalizerHandler::after_fork_child(STATE) {
    live_guard_.init();
    worker_lock_.init();
    worker_cond_.init();
    supervisor_lock_.init();
    supervisor_cond_.init();

    start_thread(state);
  }

  void FinalizerHandler::run(STATE) {
    int error = thread_.get()->fork_attached(state);
    if(error) rubinius::bug("Unable to start finalizer handler thread");
  }

  void FinalizerHandler::perform(STATE) {
    GCTokenImpl gct;
    utilities::thread::Thread::set_os_name("rbx.finalizer");

    state->vm()->thread->hard_unlock(state, gct);

    while(!exit_) {
      if(!process_list_) first_process_item();

      if(!process_list_) {
        utilities::thread::Mutex::LockGuard lg(worker_lock_);

        if(finishing_) supervisor_signal();

        // exit_ might have been set in the mean while after
        // we grabbed the worker_lock
        if(!exit_) {
          GCIndependent indy(state);
          worker_wait();
        }

        continue;
      }

      finalize(state);
      next_process_item();
    }
  }

  void FinalizerHandler::finalize(STATE) {
    state->vm()->set_call_frame(0);

    switch(process_item_kind_) {
    case eRuby: {
      CallFrame* call_frame = 0;

      if(process_item_->ruby_finalizer) {
        // Rubinius specific code. If the finalizer is cTrue, then send the
        // object the __finalize__ message.
        if(process_item_->ruby_finalizer == cTrue) {
          process_item_->object->send(state, call_frame, state->symbol("__finalize__"));
        } else {
          Array* ary = Array::create(state, 1);
          ary->set(state, 0, process_item_->object->id(state));
          process_item_->ruby_finalizer->send(state, call_frame, G(sym_call), ary);
        }
      }

      process_item_->status = FinalizeObject::eRubyFinalized;
      break;
    }
    case eNative:
      if(process_item_->finalizer) {
        (*process_item_->finalizer)(state, process_item_->object);
      }
      process_item_->status = FinalizeObject::eNativeFinalized;
      break;
    case eRelease:
      // Unhook any handle used by fi->object so that we don't accidentally
      // try and mark it later (after we've finalized it)
      if(capi::Handle* handle = process_item_->object->handle(state)) {
        handle->forget_object();
        process_item_->object->clear_handle(state);
      }

      // If the object was remembered, unremember it.
      if(process_item_->object->remembered_p()) {
        state->memory()->unremember_object(process_item_->object);
      }

      process_item_->status = FinalizeObject::eReleased;

      break;
    }
  }

  void FinalizerHandler::first_process_item() {
    if(!process_list_ && !lists_->empty()) {
      process_list_ = lists_->back();
      process_item_ = process_list_->begin();
    }
  }

  void FinalizerHandler::next_process_item() {
    if(++process_item_ == process_list_->end()) {
      switch(process_item_kind_) {
      case eRuby:
        process_item_ = process_list_->begin();
        process_item_kind_ = eNative;
        break;
      case eNative:
        process_item_ = process_list_->begin();
        process_item_kind_ = eRelease;
        break;
      case eRelease:
        delete process_list_;
        process_list_ = NULL;
        process_item_kind_ = eRuby;
        lists_->pop_back();
        break;
      }
    }
  }

  void FinalizerHandler::finish(STATE, GCToken gct) {
    if(!self_) {
      if(process_list_ || !lists_->empty() || !live_list_->empty()) {
        rubinius::bug("FinalizerHandler worker thread dead during halt");
      } else {
        return;
      }
    }

    finishing_ = true;

    while(true) {
      {
        StopTheWorld stw(state, gct, 0);

        if(!process_list_) {
          if(live_list_->empty() && lists_->empty()) break;

          // Everything is garbage when halting so keep adding live objects to
          // finalize queue until done.
          if(!live_list_->empty()) {
            for(FinalizeObjects::iterator i = live_list_->begin();
                i != live_list_->end();
                ++i)
            {
              i->queued();
            }

            queue_objects();
          }

          first_process_item();
          if(!process_list_) break;
        }
      }

      worker_signal();

      {
        utilities::thread::Mutex::LockGuard lg(supervisor_lock_);

        state->vm()->set_call_frame(0);
        GCIndependent indy(state);
        if(process_list_) supervisor_wait();
      }
    }

    if(!lists_->empty() || !live_list_->empty() || process_list_ != NULL)
      rubinius::bug("FinalizerHandler exiting with pending finalizers");

    stop_thread(state);
  }

  void FinalizerHandler::record(Object* obj, FinalizerFunction func) {
    utilities::thread::Mutex::LockGuard lg(live_guard_);

    FinalizeObject fi;
    fi.object = obj;
    fi.status = FinalizeObject::eLive;
    fi.finalizer = func;

    // Makes a copy of fi.
    live_list_->push_front(fi);
  }

  void FinalizerHandler::set_ruby_finalizer(Object* obj, Object* finalizer) {
    utilities::thread::Mutex::LockGuard lg(live_guard_);

    // Ignore Ruby finalizers created when finishing running finalizers.
    if(finishing_) return;

    // Check if the object is already in the finalizer list.
    for(FinalizeObjects::iterator i = live_list_->begin();
        i != live_list_->end();
        ++i)
    {
      if(i->object == obj) {
        if(finalizer->nil_p()) {
          live_list_->erase(i);
        } else {
          i->ruby_finalizer = finalizer;
        }
        return;
      }
    }

    // Adding a nil finalizer is only used to delete an existing finalizer,
    // which we apparently don't have if we get here.
    if(finalizer->nil_p()) {
      return;
    }

    // Ok, create it.

    FinalizeObject fi;
    fi.object = obj;
    fi.status = FinalizeObject::eLive;

    // Rubinius specific API. If the finalizer is the object, we're going to send
    // the object __finalize__. We mark that the user wants this by putting cTrue
    // as the ruby_finalizer.
    if(obj == finalizer) {
      fi.ruby_finalizer = cTrue;
    } else {
      fi.ruby_finalizer = finalizer;
    }

    // Makes a copy of fi.
    live_list_->push_front(fi);
  }

  void FinalizerHandler::queue_objects() {
    FinalizeObjects* dead_list = new FinalizeObjects();

    for(FinalizeObjects::iterator i = live_list_->begin();
        i != live_list_->end();
        /* advance is handled in the loop */)
    {
      if(i->queued_p()) {
        dead_list->push_front(*i);
        i = live_list_->erase(i);
      } else {
        ++i;
      }
    }

    if(!dead_list->empty()) {
      lists_->push_front(dead_list);
    } else {
      delete dead_list;
    }
  }

  void FinalizerHandler::start_collection(STATE) {
    if(process_item_kind_ == eRelease) {
      while(process_list_) {
        finalize(state);
        next_process_item();
      }
    }
  }

  void FinalizerHandler::finish_collection(STATE) {
    queue_objects();

    if(iterator_) {
      delete iterator_;
      iterator_ = NULL;
    }

    worker_signal();
  }

  void FinalizerHandler::supervisor_signal() {
    supervisor_cond_.signal();
  }

  void FinalizerHandler::supervisor_wait() {
    supervisor_cond_.wait(supervisor_lock_);
  }

  void FinalizerHandler::worker_signal() {
    worker_cond_.signal();
  }

  void FinalizerHandler::worker_wait() {
    worker_cond_.wait(worker_lock_);
  }

  FinalizerHandler::iterator& FinalizerHandler::begin() {
    if(iterator_) delete iterator_;
    iterator_ = new iterator(this);
    return *iterator_;
  }
}
<|endoftext|>


<commit_before>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/

#include "exception.h"
#include "qmldesignerplugin.h"
#include "qmldesignerconstants.h"
#include "pluginmanager.h"
#include "designmodewidget.h"
#include "settingspage.h"
#include "designmodecontext.h"

#include <qmljseditor/qmljseditorconstants.h>

#include <coreplugin/actionmanager/actioncontainer.h>
#include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/actionmanager/command.h>
#include <coreplugin/coreconstants.h>
#include <coreplugin/designmode.h>
#include <coreplugin/dialogs/iwizard.h>
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/editormanager/ieditorfactory.h>
#include <coreplugin/editormanager/openeditorsmodel.h>
#include <coreplugin/icontext.h>
#include <coreplugin/icore.h>
#include <coreplugin/mimedatabase.h>
#include <coreplugin/modemanager.h>

#include <extensionsystem/pluginmanager.h>

#include <utils/qtcassert.h>

#include <integrationcore.h>

#include <QtGui/QAction>

#include <QtCore/QFileInfo>
#include <QtCore/QCoreApplication>
#include <QtCore/qplugin.h>
#include <QtCore/QDebug>
#include <QtCore/QProcessEnvironment>

namespace QmlDesigner {
namespace Internal {

BauhausPlugin *BauhausPlugin::m_pluginInstance = 0;

bool shouldAssertInException()
{
    QProcessEnvironment processEnvironment = QProcessEnvironment::systemEnvironment();
    return !processEnvironment.value("QMLDESIGNER_ASSERT_ON_EXCEPTION").isEmpty();
}

BauhausPlugin::BauhausPlugin() :
    m_designerCore(0),
    m_designMode(0),
    m_isActive(false),
    m_revertToSavedAction(new QAction(this)),
    m_saveAction(new QAction(this)),
    m_saveAsAction(new QAction(this)),
    m_closeCurrentEditorAction(new QAction(this)),
    m_closeAllEditorsAction(new QAction(this)),
    m_closeOtherEditorsAction(new QAction(this))
{

    // Exceptions should never ever assert: they are handled in a number of
    // places where it is actually VALID AND EXPECTED BEHAVIOUR to get an
    // exception.
    // If you still want to see exactly where the exception originally
    // occurred, then you have various ways to do this:
    //  1. set a breakpoint on the constructor of the exception
    //  2. in gdb: "catch throw" or "catch throw Exception"
    //  3. set a breakpoint on __raise_exception()
    // And with gdb, you can even do this from your ~/.gdbinit file.
    // DnD is not working with gdb so this is still needed to get a good stacktrace

    Exception::setShouldAssert(shouldAssertInException());
}

BauhausPlugin::~BauhausPlugin()
{
    delete m_designerCore;
    Core::ICore::instance()->removeContextObject(m_context);
}

////////////////////////////////////////////////////
//
// INHERITED FROM ExtensionSystem::Plugin
//
////////////////////////////////////////////////////
bool BauhausPlugin::initialize(const QStringList & /*arguments*/, QString *error_message/* = 0*/) // =0;
{
    Core::ICore *core = Core::ICore::instance();

    const Core::Context switchContext(QmlJSEditor::Constants::C_QMLJSEDITOR_ID);

    Core::ActionManager *am = core->actionManager();

    QAction *switchAction = new QAction(tr("Switch Text/Design"), this);
    Core::Command *command = am->registerAction(switchAction, QmlDesigner::Constants::SWITCH_TEXT_DESIGN, switchContext);
    command->setDefaultKeySequence(QKeySequence(Qt::Key_F4));

    m_designerCore = new QmlDesigner::IntegrationCore;
    m_pluginInstance = this;

#ifdef Q_OS_MAC
    const QString pluginPath = QCoreApplication::applicationDirPath() + "/../PlugIns/QmlDesigner";
#else
    const QString pluginPath = QCoreApplication::applicationDirPath() + "/../"
                               + QLatin1String(IDE_LIBRARY_BASENAME) + "/qmldesigner";
#endif

    m_designerCore->pluginManager()->setPluginPaths(QStringList() << pluginPath);

    createDesignModeWidget();
    connect(switchAction, SIGNAL(triggered()), this, SLOT(switchTextDesign()));

    addAutoReleasedObject(new SettingsPage);

    m_settings.fromSettings(core->settings());

    error_message->clear();

    return true;
}

void BauhausPlugin::createDesignModeWidget()
{
    Core::ICore *creatorCore = Core::ICore::instance();
    Core::ActionManager *actionManager = creatorCore->actionManager();
    m_editorManager = creatorCore->editorManager();
    Core::ActionContainer *editMenu = actionManager->actionContainer(Core::Constants::M_EDIT);

    m_mainWidget = new DesignModeWidget;

    m_context = new DesignModeContext(m_mainWidget);
    creatorCore->addContextObject(m_context);
    Core::Context formEditorContext(Constants::C_FORMEDITOR);

    // Revert to saved
    actionManager->registerAction(m_revertToSavedAction,
                                      Core::Constants::REVERTTOSAVED, formEditorContext);
    connect(m_revertToSavedAction, SIGNAL(triggered()), m_editorManager, SLOT(revertToSaved()));

    //Save
    actionManager->registerAction(m_saveAction, Core::Constants::SAVE, formEditorContext);
    connect(m_saveAction, SIGNAL(triggered()), m_editorManager, SLOT(saveFile()));

    //Save As
    actionManager->registerAction(m_saveAsAction, Core::Constants::SAVEAS, formEditorContext);
    connect(m_saveAsAction, SIGNAL(triggered()), m_editorManager, SLOT(saveFileAs()));

    //Close Editor
    actionManager->registerAction(m_closeCurrentEditorAction, Core::Constants::CLOSE, formEditorContext);
    connect(m_closeCurrentEditorAction, SIGNAL(triggered()), m_editorManager, SLOT(closeEditor()));

    //Close All
    actionManager->registerAction(m_closeAllEditorsAction, Core::Constants::CLOSEALL, formEditorContext);
    connect(m_closeAllEditorsAction, SIGNAL(triggered()), m_editorManager, SLOT(closeAllEditors()));

    //Close All Others Action
    actionManager->registerAction(m_closeOtherEditorsAction, Core::Constants::CLOSEOTHERS, formEditorContext);
    connect(m_closeOtherEditorsAction, SIGNAL(triggered()), m_editorManager, SLOT(closeOtherEditors()));

    // Undo / Redo
    actionManager->registerAction(m_mainWidget->undoAction(), Core::Constants::UNDO, formEditorContext);
    actionManager->registerAction(m_mainWidget->redoAction(), Core::Constants::REDO, formEditorContext);

    Core::Command *command;
    command = actionManager->registerAction(m_mainWidget->deleteAction(),
                                            QmlDesigner::Constants::DELETE, formEditorContext);
    command->setDefaultKeySequence(QKeySequence::Delete);
    command->setAttribute(Core::Command::CA_Hide); // don't show delete in other modes
    editMenu->addAction(command, Core::Constants::G_EDIT_COPYPASTE);

    command = actionManager->registerAction(m_mainWidget->cutAction(),
                                            Core::Constants::CUT, formEditorContext);
    command->setDefaultKeySequence(QKeySequence::Cut);
    editMenu->addAction(command, Core::Constants::G_EDIT_COPYPASTE);

    command = actionManager->registerAction(m_mainWidget->copyAction(),
                                            Core::Constants::COPY, formEditorContext);
    command->setDefaultKeySequence(QKeySequence::Copy);
    editMenu->addAction(command, Core::Constants::G_EDIT_COPYPASTE);

    command = actionManager->registerAction(m_mainWidget->pasteAction(),
                                            Core::Constants::PASTE, formEditorContext);
    command->setDefaultKeySequence(QKeySequence::Paste);
    editMenu->addAction(command, Core::Constants::G_EDIT_COPYPASTE);

    command = actionManager->registerAction(m_mainWidget->selectAllAction(),
                                            Core::Constants::SELECTALL, formEditorContext);
    command->setDefaultKeySequence(QKeySequence::SelectAll);
    editMenu->addAction(command, Core::Constants::G_EDIT_SELECTALL);

    Core::ActionContainer *viewsMenu = actionManager->actionContainer(Core::Constants::M_WINDOW_VIEWS);

    command = actionManager->registerAction(m_mainWidget->toggleLeftSidebarAction(),
                                            Constants::TOGGLE_LEFT_SIDEBAR, formEditorContext);
    command->setAttribute(Core::Command::CA_Hide);
    command->setDefaultKeySequence(QKeySequence("Ctrl+Alt+0"));
    viewsMenu->addAction(command);

    command = actionManager->registerAction(m_mainWidget->toggleRightSidebarAction(),
                                            Constants::TOGGLE_RIGHT_SIDEBAR, formEditorContext);
    command->setAttribute(Core::Command::CA_Hide);
    command->setDefaultKeySequence(QKeySequence("Ctrl+Alt+Shift+0"));
    viewsMenu->addAction(command);

    command = actionManager->registerAction(m_mainWidget->restoreDefaultViewAction(),
                                            Constants::RESTORE_DEFAULT_VIEW, formEditorContext);
    command->setAttribute(Core::Command::CA_Hide);
    viewsMenu->addAction(command);

    command = actionManager->registerAction(m_mainWidget->hideSidebarsAction(),
                                            Core::Constants::TOGGLE_SIDEBAR, formEditorContext);

#ifdef Q_OS_MACX
    // add second shortcut to trigger delete
    QAction *deleteAction = new QAction(m_mainWidget);
    deleteAction->setShortcut(QKeySequence(QLatin1String("Backspace")));
    connect(deleteAction, SIGNAL(triggered()), m_mainWidget->deleteAction(),
            SIGNAL(triggered()));

    m_mainWidget->addAction(deleteAction);
#endif // Q_OS_MACX

    connect(m_editorManager, SIGNAL(currentEditorChanged(Core::IEditor*)),
            this, SLOT(updateEditor(Core::IEditor*)));

    connect(m_editorManager, SIGNAL(editorsClosed(QList<Core::IEditor*>)),
            this, SLOT(textEditorsClosed(QList<Core::IEditor*>)));

    connect(creatorCore, SIGNAL(contextChanged(Core::IContext*,Core::Context)),
            this, SLOT(contextChanged(Core::IContext*,Core::Context)));

}

void BauhausPlugin::updateEditor(Core::IEditor *editor)
{
    Core::ICore *creatorCore = Core::ICore::instance();
    if (editor && editor->id() == QmlJSEditor::Constants::C_QMLJSEDITOR_ID
        && creatorCore->modeManager()->currentMode() == m_designMode)
    {
        m_mainWidget->showEditor(editor);
    }
}

void BauhausPlugin::contextChanged(Core::IContext *context, const Core::Context &additionalContexts)
{
    Q_UNUSED(context)

    foreach (int additionalContext, additionalContexts) {
        if (m_context->context().contains(additionalContext)) {
            m_isActive = true;
            m_mainWidget->showEditor(m_editorManager->currentEditor());
            return;
        }
    }

    if (m_isActive) {
        m_isActive = false;
        m_mainWidget->showEditor(0);
    }
}

void BauhausPlugin::textEditorsClosed(QList<Core::IEditor*> editors)
{
    m_mainWidget->closeEditors(editors);
}

// copied from EditorManager::updateActions
void BauhausPlugin::updateActions(Core::IEditor* editor)
{
    Core::IEditor *curEditor = editor;
    int openedCount = m_editorManager->openedEditors().count()
                      + m_editorManager->openedEditorsModel()->restoredEditors().count();

    QString fName;
    if (curEditor) {
        if (!curEditor->file()->fileName().isEmpty()) {
            QFileInfo fi(curEditor->file()->fileName());
            fName = fi.fileName();
        } else {
            fName = curEditor->displayName();
        }
    }

    m_saveAction->setEnabled(curEditor != 0 && curEditor->file()->isModified());
    m_saveAsAction->setEnabled(curEditor != 0 && curEditor->file()->isSaveAsAllowed());
    m_revertToSavedAction->setEnabled(curEditor != 0
                                      && !curEditor->file()->fileName().isEmpty()
                                      && curEditor->file()->isModified());

    QString quotedName;
    if (!fName.isEmpty())
        quotedName = '"' + fName + '"';
    m_saveAsAction->setText(tr("Save %1 As...").arg(quotedName));
    m_saveAction->setText(tr("&Save %1").arg(quotedName));
    m_revertToSavedAction->setText(tr("Revert %1 to Saved").arg(quotedName));

    m_closeCurrentEditorAction->setEnabled(curEditor != 0);
    m_closeCurrentEditorAction->setText(tr("Close %1").arg(quotedName));
    m_closeAllEditorsAction->setEnabled(openedCount > 0);
    m_closeOtherEditorsAction->setEnabled(openedCount > 1);
    m_closeOtherEditorsAction->setText((openedCount > 1 ? tr("Close All Except %1").arg(quotedName) : tr("Close Others")));
}

void BauhausPlugin::extensionsInitialized()
{
    m_designMode = ExtensionSystem::PluginManager::instance()->getObject<Core::DesignMode>();

    m_mimeTypes << "application/x-qml" << "application/javascript"
                << "application/x-javascript" << "text/javascript";

    m_designMode->registerDesignWidget(m_mainWidget, m_mimeTypes, m_context->context());
    connect(m_designMode, SIGNAL(actionsUpdated(Core::IEditor*)), SLOT(updateActions(Core::IEditor*)));
}

BauhausPlugin *BauhausPlugin::pluginInstance()
{
    return m_pluginInstance;
}

void BauhausPlugin::switchTextDesign()
{
    Core::ModeManager *modeManager = Core::ModeManager::instance();
    Core::EditorManager *editorManager = Core::EditorManager::instance();
    Core::IEditor *editor = editorManager->currentEditor();

    if (modeManager->currentMode()->id() == Core::Constants::MODE_EDIT) {
        if (editor->id() == QmlJSEditor::Constants::C_QMLJSEDITOR_ID) {
            modeManager->activateMode(Core::Constants::MODE_DESIGN);
            m_mainWidget->setFocus();
        }
    } else if (modeManager->currentMode()->id() == Core::Constants::MODE_DESIGN) {
        modeManager->activateMode(Core::Constants::MODE_EDIT);
    }
}

DesignerSettings BauhausPlugin::settings() const
{
    return m_settings;
}

void BauhausPlugin::setSettings(const DesignerSettings &s)
{
    if (s != m_settings) {
        m_settings = s;
        if (QSettings *settings = Core::ICore::instance()->settings())
            m_settings.toSettings(settings);
    }
}

}
}

Q_EXPORT_PLUGIN(QmlDesigner::Internal::BauhausPlugin)
<commit_msg>Core::Context: fix regression introduced by c7e8b51d<commit_after>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/

#include "exception.h"
#include "qmldesignerplugin.h"
#include "qmldesignerconstants.h"
#include "pluginmanager.h"
#include "designmodewidget.h"
#include "settingspage.h"
#include "designmodecontext.h"

#include <qmljseditor/qmljseditorconstants.h>

#include <coreplugin/actionmanager/actioncontainer.h>
#include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/actionmanager/command.h>
#include <coreplugin/coreconstants.h>
#include <coreplugin/designmode.h>
#include <coreplugin/dialogs/iwizard.h>
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/editormanager/ieditorfactory.h>
#include <coreplugin/editormanager/openeditorsmodel.h>
#include <coreplugin/icontext.h>
#include <coreplugin/icore.h>
#include <coreplugin/mimedatabase.h>
#include <coreplugin/modemanager.h>

#include <extensionsystem/pluginmanager.h>

#include <utils/qtcassert.h>

#include <integrationcore.h>

#include <QtGui/QAction>

#include <QtCore/QFileInfo>
#include <QtCore/QCoreApplication>
#include <QtCore/qplugin.h>
#include <QtCore/QDebug>
#include <QtCore/QProcessEnvironment>

namespace QmlDesigner {
namespace Internal {

BauhausPlugin *BauhausPlugin::m_pluginInstance = 0;

bool shouldAssertInException()
{
    QProcessEnvironment processEnvironment = QProcessEnvironment::systemEnvironment();
    return !processEnvironment.value("QMLDESIGNER_ASSERT_ON_EXCEPTION").isEmpty();
}

BauhausPlugin::BauhausPlugin() :
    m_designerCore(0),
    m_designMode(0),
    m_isActive(false),
    m_revertToSavedAction(new QAction(this)),
    m_saveAction(new QAction(this)),
    m_saveAsAction(new QAction(this)),
    m_closeCurrentEditorAction(new QAction(this)),
    m_closeAllEditorsAction(new QAction(this)),
    m_closeOtherEditorsAction(new QAction(this))
{

    // Exceptions should never ever assert: they are handled in a number of
    // places where it is actually VALID AND EXPECTED BEHAVIOUR to get an
    // exception.
    // If you still want to see exactly where the exception originally
    // occurred, then you have various ways to do this:
    //  1. set a breakpoint on the constructor of the exception
    //  2. in gdb: "catch throw" or "catch throw Exception"
    //  3. set a breakpoint on __raise_exception()
    // And with gdb, you can even do this from your ~/.gdbinit file.
    // DnD is not working with gdb so this is still needed to get a good stacktrace

    Exception::setShouldAssert(shouldAssertInException());
}

BauhausPlugin::~BauhausPlugin()
{
    delete m_designerCore;
    Core::ICore::instance()->removeContextObject(m_context);
}

////////////////////////////////////////////////////
//
// INHERITED FROM ExtensionSystem::Plugin
//
////////////////////////////////////////////////////
bool BauhausPlugin::initialize(const QStringList & /*arguments*/, QString *error_message/* = 0*/) // =0;
{
    Core::ICore *core = Core::ICore::instance();

    const Core::Context switchContext(QmlDesigner::Constants::C_FORMEDITOR,
        QmlJSEditor::Constants::C_QMLJSEDITOR_ID);

    Core::ActionManager *am = core->actionManager();

    QAction *switchAction = new QAction(tr("Switch Text/Design"), this);
    Core::Command *command = am->registerAction(switchAction, QmlDesigner::Constants::SWITCH_TEXT_DESIGN, switchContext);
    command->setDefaultKeySequence(QKeySequence(Qt::Key_F4));

    m_designerCore = new QmlDesigner::IntegrationCore;
    m_pluginInstance = this;

#ifdef Q_OS_MAC
    const QString pluginPath = QCoreApplication::applicationDirPath() + "/../PlugIns/QmlDesigner";
#else
    const QString pluginPath = QCoreApplication::applicationDirPath() + "/../"
                               + QLatin1String(IDE_LIBRARY_BASENAME) + "/qmldesigner";
#endif

    m_designerCore->pluginManager()->setPluginPaths(QStringList() << pluginPath);

    createDesignModeWidget();
    connect(switchAction, SIGNAL(triggered()), this, SLOT(switchTextDesign()));

    addAutoReleasedObject(new SettingsPage);

    m_settings.fromSettings(core->settings());

    error_message->clear();

    return true;
}

void BauhausPlugin::createDesignModeWidget()
{
    Core::ICore *creatorCore = Core::ICore::instance();
    Core::ActionManager *actionManager = creatorCore->actionManager();
    m_editorManager = creatorCore->editorManager();
    Core::ActionContainer *editMenu = actionManager->actionContainer(Core::Constants::M_EDIT);

    m_mainWidget = new DesignModeWidget;

    m_context = new DesignModeContext(m_mainWidget);
    creatorCore->addContextObject(m_context);
    Core::Context formEditorContext(Constants::C_FORMEDITOR);

    // Revert to saved
    actionManager->registerAction(m_revertToSavedAction,
                                      Core::Constants::REVERTTOSAVED, formEditorContext);
    connect(m_revertToSavedAction, SIGNAL(triggered()), m_editorManager, SLOT(revertToSaved()));

    //Save
    actionManager->registerAction(m_saveAction, Core::Constants::SAVE, formEditorContext);
    connect(m_saveAction, SIGNAL(triggered()), m_editorManager, SLOT(saveFile()));

    //Save As
    actionManager->registerAction(m_saveAsAction, Core::Constants::SAVEAS, formEditorContext);
    connect(m_saveAsAction, SIGNAL(triggered()), m_editorManager, SLOT(saveFileAs()));

    //Close Editor
    actionManager->registerAction(m_closeCurrentEditorAction, Core::Constants::CLOSE, formEditorContext);
    connect(m_closeCurrentEditorAction, SIGNAL(triggered()), m_editorManager, SLOT(closeEditor()));

    //Close All
    actionManager->registerAction(m_closeAllEditorsAction, Core::Constants::CLOSEALL, formEditorContext);
    connect(m_closeAllEditorsAction, SIGNAL(triggered()), m_editorManager, SLOT(closeAllEditors()));

    //Close All Others Action
    actionManager->registerAction(m_closeOtherEditorsAction, Core::Constants::CLOSEOTHERS, formEditorContext);
    connect(m_closeOtherEditorsAction, SIGNAL(triggered()), m_editorManager, SLOT(closeOtherEditors()));

    // Undo / Redo
    actionManager->registerAction(m_mainWidget->undoAction(), Core::Constants::UNDO, formEditorContext);
    actionManager->registerAction(m_mainWidget->redoAction(), Core::Constants::REDO, formEditorContext);

    Core::Command *command;
    command = actionManager->registerAction(m_mainWidget->deleteAction(),
                                            QmlDesigner::Constants::DELETE, formEditorContext);
    command->setDefaultKeySequence(QKeySequence::Delete);
    command->setAttribute(Core::Command::CA_Hide); // don't show delete in other modes
    editMenu->addAction(command, Core::Constants::G_EDIT_COPYPASTE);

    command = actionManager->registerAction(m_mainWidget->cutAction(),
                                            Core::Constants::CUT, formEditorContext);
    command->setDefaultKeySequence(QKeySequence::Cut);
    editMenu->addAction(command, Core::Constants::G_EDIT_COPYPASTE);

    command = actionManager->registerAction(m_mainWidget->copyAction(),
                                            Core::Constants::COPY, formEditorContext);
    command->setDefaultKeySequence(QKeySequence::Copy);
    editMenu->addAction(command, Core::Constants::G_EDIT_COPYPASTE);

    command = actionManager->registerAction(m_mainWidget->pasteAction(),
                                            Core::Constants::PASTE, formEditorContext);
    command->setDefaultKeySequence(QKeySequence::Paste);
    editMenu->addAction(command, Core::Constants::G_EDIT_COPYPASTE);

    command = actionManager->registerAction(m_mainWidget->selectAllAction(),
                                            Core::Constants::SELECTALL, formEditorContext);
    command->setDefaultKeySequence(QKeySequence::SelectAll);
    editMenu->addAction(command, Core::Constants::G_EDIT_SELECTALL);

    Core::ActionContainer *viewsMenu = actionManager->actionContainer(Core::Constants::M_WINDOW_VIEWS);

    command = actionManager->registerAction(m_mainWidget->toggleLeftSidebarAction(),
                                            Constants::TOGGLE_LEFT_SIDEBAR, formEditorContext);
    command->setAttribute(Core::Command::CA_Hide);
    command->setDefaultKeySequence(QKeySequence("Ctrl+Alt+0"));
    viewsMenu->addAction(command);

    command = actionManager->registerAction(m_mainWidget->toggleRightSidebarAction(),
                                            Constants::TOGGLE_RIGHT_SIDEBAR, formEditorContext);
    command->setAttribute(Core::Command::CA_Hide);
    command->setDefaultKeySequence(QKeySequence("Ctrl+Alt+Shift+0"));
    viewsMenu->addAction(command);

    command = actionManager->registerAction(m_mainWidget->restoreDefaultViewAction(),
                                            Constants::RESTORE_DEFAULT_VIEW, formEditorContext);
    command->setAttribute(Core::Command::CA_Hide);
    viewsMenu->addAction(command);

    command = actionManager->registerAction(m_mainWidget->hideSidebarsAction(),
                                            Core::Constants::TOGGLE_SIDEBAR, formEditorContext);

#ifdef Q_OS_MACX
    // add second shortcut to trigger delete
    QAction *deleteAction = new QAction(m_mainWidget);
    deleteAction->setShortcut(QKeySequence(QLatin1String("Backspace")));
    connect(deleteAction, SIGNAL(triggered()), m_mainWidget->deleteAction(),
            SIGNAL(triggered()));

    m_mainWidget->addAction(deleteAction);
#endif // Q_OS_MACX

    connect(m_editorManager, SIGNAL(currentEditorChanged(Core::IEditor*)),
            this, SLOT(updateEditor(Core::IEditor*)));

    connect(m_editorManager, SIGNAL(editorsClosed(QList<Core::IEditor*>)),
            this, SLOT(textEditorsClosed(QList<Core::IEditor*>)));

    connect(creatorCore, SIGNAL(contextChanged(Core::IContext*,Core::Context)),
            this, SLOT(contextChanged(Core::IContext*,Core::Context)));

}

void BauhausPlugin::updateEditor(Core::IEditor *editor)
{
    Core::ICore *creatorCore = Core::ICore::instance();
    if (editor && editor->id() == QmlJSEditor::Constants::C_QMLJSEDITOR_ID
        && creatorCore->modeManager()->currentMode() == m_designMode)
    {
        m_mainWidget->showEditor(editor);
    }
}

void BauhausPlugin::contextChanged(Core::IContext *context, const Core::Context &additionalContexts)
{
    Q_UNUSED(context)

    foreach (int additionalContext, additionalContexts) {
        if (m_context->context().contains(additionalContext)) {
            m_isActive = true;
            m_mainWidget->showEditor(m_editorManager->currentEditor());
            return;
        }
    }

    if (m_isActive) {
        m_isActive = false;
        m_mainWidget->showEditor(0);
    }
}

void BauhausPlugin::textEditorsClosed(QList<Core::IEditor*> editors)
{
    m_mainWidget->closeEditors(editors);
}

// copied from EditorManager::updateActions
void BauhausPlugin::updateActions(Core::IEditor* editor)
{
    Core::IEditor *curEditor = editor;
    int openedCount = m_editorManager->openedEditors().count()
                      + m_editorManager->openedEditorsModel()->restoredEditors().count();

    QString fName;
    if (curEditor) {
        if (!curEditor->file()->fileName().isEmpty()) {
            QFileInfo fi(curEditor->file()->fileName());
            fName = fi.fileName();
        } else {
            fName = curEditor->displayName();
        }
    }

    m_saveAction->setEnabled(curEditor != 0 && curEditor->file()->isModified());
    m_saveAsAction->setEnabled(curEditor != 0 && curEditor->file()->isSaveAsAllowed());
    m_revertToSavedAction->setEnabled(curEditor != 0
                                      && !curEditor->file()->fileName().isEmpty()
                                      && curEditor->file()->isModified());

    QString quotedName;
    if (!fName.isEmpty())
        quotedName = '"' + fName + '"';
    m_saveAsAction->setText(tr("Save %1 As...").arg(quotedName));
    m_saveAction->setText(tr("&Save %1").arg(quotedName));
    m_revertToSavedAction->setText(tr("Revert %1 to Saved").arg(quotedName));

    m_closeCurrentEditorAction->setEnabled(curEditor != 0);
    m_closeCurrentEditorAction->setText(tr("Close %1").arg(quotedName));
    m_closeAllEditorsAction->setEnabled(openedCount > 0);
    m_closeOtherEditorsAction->setEnabled(openedCount > 1);
    m_closeOtherEditorsAction->setText((openedCount > 1 ? tr("Close All Except %1").arg(quotedName) : tr("Close Others")));
}

void BauhausPlugin::extensionsInitialized()
{
    m_designMode = ExtensionSystem::PluginManager::instance()->getObject<Core::DesignMode>();

    m_mimeTypes << "application/x-qml" << "application/javascript"
                << "application/x-javascript" << "text/javascript";

    m_designMode->registerDesignWidget(m_mainWidget, m_mimeTypes, m_context->context());
    connect(m_designMode, SIGNAL(actionsUpdated(Core::IEditor*)), SLOT(updateActions(Core::IEditor*)));
}

BauhausPlugin *BauhausPlugin::pluginInstance()
{
    return m_pluginInstance;
}

void BauhausPlugin::switchTextDesign()
{
    Core::ModeManager *modeManager = Core::ModeManager::instance();
    Core::EditorManager *editorManager = Core::EditorManager::instance();
    Core::IEditor *editor = editorManager->currentEditor();

    if (modeManager->currentMode()->id() == Core::Constants::MODE_EDIT) {
        if (editor->id() == QmlJSEditor::Constants::C_QMLJSEDITOR_ID) {
            modeManager->activateMode(Core::Constants::MODE_DESIGN);
            m_mainWidget->setFocus();
        }
    } else if (modeManager->currentMode()->id() == Core::Constants::MODE_DESIGN) {
        modeManager->activateMode(Core::Constants::MODE_EDIT);
    }
}

DesignerSettings BauhausPlugin::settings() const
{
    return m_settings;
}

void BauhausPlugin::setSettings(const DesignerSettings &s)
{
    if (s != m_settings) {
        m_settings = s;
        if (QSettings *settings = Core::ICore::instance()->settings())
            m_settings.toSettings(settings);
    }
}

}
}

Q_EXPORT_PLUGIN(QmlDesigner::Internal::BauhausPlugin)
<|endoftext|>


<commit_before>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (info@qt.nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at info@qt.nokia.com.
**
**************************************************************************/

#include "checkoutwizardpage.h"

namespace Subversion {
namespace Internal {

CheckoutWizardPage::CheckoutWizardPage(QWidget *parent) :
    VCSBase::BaseCheckoutWizardPage(parent)
{
    setTitle(tr("Location"));
    setSubTitle(tr("Specify repository URL, checkout directory and path."));
    setRepositoryLabel(tr("Repository:"));
    setBranchSelectorVisible(false);
}

QString CheckoutWizardPage::directoryFromRepository(const QString &repoIn) const
{
    /* Try to figure out a good directory name from something like:
     * "svn://<server>/path1/project" -> project */

    QString repo = repoIn.trimmed();
    const QChar slash = QLatin1Char('/');
    // remove host
    const int slashPos = repo.lastIndexOf(slash);
    if (slashPos != -1)
        repo.remove(0, slashPos + 1);
    // fix invalid characters
    const QChar dash = QLatin1Char('-');
    repo.replace(QLatin1Char('.'), QLatin1Char('-'));
    return repo;
}

} // namespace Internal
} // namespace Subversion
<commit_msg>Remove code that has no effect<commit_after>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (info@qt.nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at info@qt.nokia.com.
**
**************************************************************************/

#include "checkoutwizardpage.h"

namespace Subversion {
namespace Internal {

CheckoutWizardPage::CheckoutWizardPage(QWidget *parent) :
    VCSBase::BaseCheckoutWizardPage(parent)
{
    setTitle(tr("Location"));
    setSubTitle(tr("Specify repository URL, checkout directory and path."));
    setRepositoryLabel(tr("Repository:"));
    setBranchSelectorVisible(false);
}

QString CheckoutWizardPage::directoryFromRepository(const QString &repoIn) const
{
    /* Try to figure out a good directory name from something like:
     * "svn://<server>/path1/project" -> project */

    QString repo = repoIn.trimmed();
    const QChar slash = QLatin1Char('/');
    // remove host
    const int slashPos = repo.lastIndexOf(slash);
    if (slashPos != -1)
        repo.remove(0, slashPos + 1);
    // fix invalid characters
    repo.replace(QLatin1Char('.'), QLatin1Char('-'));
    return repo;
}

} // namespace Internal
} // namespace Subversion
<|endoftext|>


<commit_before>
#include <iostream>

#include <cinatra/cinatra.h>
#include <cinatra/middleware/cookies.hpp>
#include <cinatra/middleware/session.hpp>
#include <cinatra_http/websocket.h>
using namespace cinatra;

struct mylog{
    bool before(cinatra::request const& req, cinatra::response& res)
    {
        std::cout << "log before" << std::endl;
        return true;
    }

    bool after(const std::string& result, cinatra::request const& req, cinatra::response& res)
    {
        std::cout << "log after " <<result<< std::endl;
        res.response_text(result);
        return true;
    }
};

struct validate{
    bool before(cinatra::request const& req, cinatra::response& res)
    {
        std::cout << "validate before" << std::endl;
        return true;
    }

    bool after(const std::string& result, cinatra::request const& req, cinatra::response& res)
    {
        std::cout << "validate after" << std::endl;
        res.response_text(result);
        return true;
    }
};

struct student{
    int id;
    std::string name;
    int age;
};
REFLECTION(student, id, name, age)

struct person{
    int get_id(const request& req, response& res){
        return 20;
    }

    std::string get_ip(const request& req, response& res){
        return "Your IP address is " + req.remote_endpoint().address().to_string();
    }

    void get_json(const request& req, response& res){
        student s = {1, "tom", 19};
        iguana::string_stream ss;
        iguana::json::to_json(ss, s);
        res.response_text(ss.str());
    }
};

int main()
{
    cinatra::cinatra app;
    app.register_handler<GET>("/", [](const request& req, response& res){
        return "hello";
    }, mylog{});

    app.register_handler<POST>("/", [](const request& req, response& res){
        return 20;
    }, mylog{}, validate{});

    app.register_handler<GET>("/ip", [](const request& req, response& res){
        res.response_text("Your IP address is " + req.remote_endpoint().address().to_string());
    });

    person p;
    app.register_handler<GET>("/get_id", &person::get_id, person{}, mylog{});
    app.register_handler<GET>("/get_ip", &person::get_ip, p, mylog{});
    app.register_handler<GET>("/test_json", &person::get_json, p);

	app.set_static_path("./static");
	app.listen("0.0.0.0", "8080");
	app.run();

	return 0;
}<commit_msg>update<commit_after>
#include <iostream>

#include <cinatra/cinatra.h>
#include <cinatra/middleware/cookies.hpp>
#include <cinatra/middleware/session.hpp>
#include <cinatra_http/websocket.h>
using namespace cinatra;

struct mylog{
    bool before(cinatra::request const& req, cinatra::response& res)
    {
        std::cout << "log before" << std::endl;
        return true;
    }

    bool after(const std::string& result, cinatra::request const& req, cinatra::response& res)
    {
        std::cout << "log after " <<result<< std::endl;
        res.response_text(result);
        return true;
    }
};

struct validate{
    bool before(cinatra::request const& req, cinatra::response& res)
    {
        std::cout << "validate before" << std::endl;
        return true;
    }

    bool after(const std::string& result, cinatra::request const& req, cinatra::response& res)
    {
        std::cout << "validate after" << std::endl;
        res.response_text(result);
        return true;
    }
};

struct student{
    int id;
    std::string name;
    int age;
};
REFLECTION(student, id, name, age)

struct person{
    int get_id(const request& req, response& res){
        return 20;
    }

    std::string get_ip(const request& req, response& res){
        return "Your IP address is " + req.remote_endpoint().address().to_string();
    }

    void get_json(const request& req, response& res){
        student s = {1, "tom", 19};
        iguana::string_stream ss;
        iguana::json::to_json(ss, s);
        res.response_text(ss.str());
    }
};

int main()
{
    cinatra::cinatra app;
    app.register_handler<GET>("/", [](const request& req, response& res){
        return "hello";
    }, mylog{});

    app.register_handler<POST>("/", [](const request& req, response& res){
        return 20;
    }, mylog{}, validate{});

    app.register_handler<GET>("/ip", [](const request& req, response& res){
        res.response_text("Your IP address is " + req.remote_endpoint().address().to_string());
    });

    person p;
    app.register_handler<GET>("/get_id", &person::get_id, person{}, mylog{});
    app.register_handler<GET>("/get_ip", &person::get_ip, p, mylog{});
    app.register_handler<GET>("/test_json", &person::get_json, p);

    app.register_handler<GET>("/ws_echo", [](cinatra::request const& req, cinatra::response& res)
    {
        auto client_key = cinatra::websocket::websocket_connection::is_websocket_handshake(req);
        if (client_key.empty())
        {
            res.response_text("Not a websocket handshake");
            return;
        }

        cinatra::websocket::ws_config_t cfg =
        {
            // on_start
            [](cinatra::websocket::ws_conn_ptr_t conn)
            {
                static const std::string hello = "Hello websocket!";
                conn->async_send_msg(hello, cinatra::websocket::TEXT, [](boost::system::error_code const& ec)
                {
                    if (ec)
                    {
                        std::cout << "Send websocket hello failed: " << ec.message() << std::endl;
                    }
                });
            },
            // on_message
            [](cinatra::websocket::ws_conn_ptr_t conn, boost::string_ref msg, cinatra::websocket::opcode_t opc)
            {
                auto back_msg = std::make_shared<std::string>(msg.to_string());
                conn->async_send_msg(*back_msg, opc, [back_msg](boost::system::error_code const& ec)
                {
                    if (ec)
                    {
                        std::cout << "Send websocket hello failed: " << ec.message() << std::endl;
                    }
                });
            },
            nullptr, nullptr, nullptr,
            // on_error
            [](boost::system::error_code const& ec)
            {
                std::cout << "upgrade to websocket failed:" << ec.message() << std::endl;
            }
        };
        cinatra::websocket::websocket_connection::upgrade_to_websocket(req, res, client_key, cfg);
    });

	app.set_static_path("./static");
	app.listen("0.0.0.0", "8080");
	app.run();

	return 0;
}<|endoftext|>


<commit_before>/*
 * Copyright 2016-2017 libfpta authors: please see AUTHORS file.
 *
 * This file is part of libfpta, aka "Fast Positive Tables".
 *
 * libfpta is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * libfpta 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with libfpta.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "fpta_test.h"

static const char testdb_name[] = "ut_open.fpta";
static const char testdb_name_lck[] = "ut_open.fpta" MDBX_LOCK_SUFFIX;

TEST(Open, Trivia) {
  /* Тривиальный тест открытия/создания БД во всех режимах durability.
   * Корректность самих режимов не проверяется. */
  if (REMOVE_FILE(testdb_name) != 0)
    ASSERT_EQ(ENOENT, errno);
  if (REMOVE_FILE(testdb_name_lck) != 0)
    ASSERT_EQ(ENOENT, errno);

  fpta_db *db = (fpta_db *)&db;
  EXPECT_EQ(ENOENT,
            fpta_db_open(testdb_name, fpta_readonly, 0644, 1, false, &db));
  EXPECT_EQ(nullptr, db);
  ASSERT_TRUE(REMOVE_FILE(testdb_name) != 0 && errno == ENOENT);
  ASSERT_TRUE(REMOVE_FILE(testdb_name_lck) != 0 && errno == ENOENT);

  EXPECT_EQ(FPTA_SUCCESS,
            fpta_db_open(testdb_name, fpta_sync, 0644, 1, false, &db));
  EXPECT_NE(nullptr, db);
  EXPECT_EQ(FPTA_SUCCESS, fpta_db_close(db));
  ASSERT_TRUE(REMOVE_FILE(testdb_name) == 0);
  ASSERT_TRUE(REMOVE_FILE(testdb_name_lck) == 0);

  EXPECT_EQ(FPTA_SUCCESS,
            fpta_db_open(testdb_name, fpta_sync, 0644, 1, false, &db));
  EXPECT_NE(nullptr, db);
  EXPECT_EQ(FPTA_SUCCESS, fpta_db_close(db));
  ASSERT_TRUE(REMOVE_FILE(testdb_name) == 0);
  ASSERT_TRUE(REMOVE_FILE(testdb_name_lck) == 0);

  EXPECT_EQ(FPTA_SUCCESS,
            fpta_db_open(testdb_name, fpta_lazy, 0644, 1, false, &db));
  EXPECT_NE(nullptr, db);
  EXPECT_EQ(FPTA_SUCCESS, fpta_db_close(db));
  ASSERT_TRUE(REMOVE_FILE(testdb_name) == 0);
  ASSERT_TRUE(REMOVE_FILE(testdb_name_lck) == 0);

  EXPECT_EQ(FPTA_SUCCESS,
            fpta_db_open(testdb_name, fpta_async, 0644, 1, false, &db));
  EXPECT_NE(nullptr, db);
  EXPECT_EQ(FPTA_SUCCESS, fpta_db_close(db));
  ASSERT_TRUE(REMOVE_FILE(testdb_name) == 0);
  ASSERT_TRUE(REMOVE_FILE(testdb_name_lck) == 0);
}

int main(int argc, char **argv) {
  testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}
<commit_msg>fpta: minor fix 1open unit-test.<commit_after>/*
 * Copyright 2016-2017 libfpta authors: please see AUTHORS file.
 *
 * This file is part of libfpta, aka "Fast Positive Tables".
 *
 * libfpta is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * libfpta 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with libfpta.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "fpta_test.h"

static const char testdb_name[] = "ut_open.fpta";
static const char testdb_name_lck[] = "ut_open.fpta" MDBX_LOCK_SUFFIX;

TEST(Open, Trivia) {
  /* Тривиальный тест открытия/создания БД во всех режимах durability.
   * Корректность самих режимов не проверяется. */
  if (REMOVE_FILE(testdb_name) != 0)
    ASSERT_EQ(ENOENT, errno);
  if (REMOVE_FILE(testdb_name_lck) != 0)
    ASSERT_EQ(ENOENT, errno);

  fpta_db *db = (fpta_db *)&db;
  EXPECT_EQ(ENOENT,
            fpta_db_open(testdb_name, fpta_readonly, 0644, 1, false, &db));
  EXPECT_EQ(nullptr, db);
  ASSERT_TRUE(REMOVE_FILE(testdb_name) != 0 && errno == ENOENT);
  ASSERT_TRUE(REMOVE_FILE(testdb_name_lck) != 0 && errno == ENOENT);

  EXPECT_EQ(FPTA_SUCCESS,
            fpta_db_open(testdb_name, fpta_sync, 0644, 1, false, &db));
  EXPECT_NE(nullptr, db);
  EXPECT_EQ(FPTA_SUCCESS, fpta_db_close(db));
  ASSERT_TRUE(REMOVE_FILE(testdb_name) == 0);
  ASSERT_TRUE(REMOVE_FILE(testdb_name_lck) == 0);

  EXPECT_EQ(FPTA_SUCCESS,
            fpta_db_open(testdb_name, fpta_sync, 0644, 1, true, &db));
  EXPECT_NE(nullptr, db);
  EXPECT_EQ(FPTA_SUCCESS, fpta_db_close(db));
  ASSERT_TRUE(REMOVE_FILE(testdb_name) == 0);
  ASSERT_TRUE(REMOVE_FILE(testdb_name_lck) == 0);

  EXPECT_EQ(FPTA_SUCCESS,
            fpta_db_open(testdb_name, fpta_lazy, 0644, 1, false, &db));
  EXPECT_NE(nullptr, db);
  EXPECT_EQ(FPTA_SUCCESS, fpta_db_close(db));
  ASSERT_TRUE(REMOVE_FILE(testdb_name) == 0);
  ASSERT_TRUE(REMOVE_FILE(testdb_name_lck) == 0);

  EXPECT_EQ(FPTA_SUCCESS,
            fpta_db_open(testdb_name, fpta_async, 0644, 1, false, &db));
  EXPECT_NE(nullptr, db);
  EXPECT_EQ(FPTA_SUCCESS, fpta_db_close(db));
  ASSERT_TRUE(REMOVE_FILE(testdb_name) == 0);
  ASSERT_TRUE(REMOVE_FILE(testdb_name_lck) == 0);
}

int main(int argc, char **argv) {
  testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}
<|endoftext|>


<commit_before>// @(#)root/test:$Name:  $:$Id: Event.cxx,v 1.13 2001/10/10 20:57:51 brun Exp $
// Author: Rene Brun   19/08/96

////////////////////////////////////////////////////////////////////////
//
//                       Event and Track classes
//                       =======================
//
//  The Event class is a naive/simple example of an event structure.
//     public:
//        char           fType[20];
//        Int_t          fNtrack;
//        Int_t          fNseg;
//        Int_t          fNvertex;
//        UInt_t         fFlag;
//        Float_t        fTemperature;
//        Int_t          fMeasures[10];
//        Float_t        fMatrix[4][4];
//        Float_t       *fClosestDistance; //[fNvertex] indexed array!
//        EventHeader    fEvtHdr;
//        TClonesArray  *fTracks;
//        TRefArray     *fHighPt;            //array of High Pt tracks only
//        TRefArray     *fMuons;             //array of Muon tracks only
//        TRef           fLastTrack;         //pointer to last track
//        TH1F          *fH;
//
//   The EventHeader class has 3 data members (integers):
//     public:
//        Int_t          fEvtNum;
//        Int_t          fRun;
//        Int_t          fDate;
//
//
//   The Event data member fTracks is a pointer to a TClonesArray.
//   It is an array of a variable number of tracks per event.
//   Each element of the array is an object of class Track with the members:
//     private:
//        Float_t      fPx;           //X component of the momentum
//        Float_t      fPy;           //Y component of the momentum
//        Float_t      fPz;           //Z component of the momentum
//        Float_t      fRandom;       //A random track quantity
//        Float_t      fMass2;        //The mass square of this particle
//        Float_t      fBx;           //X intercept at the vertex
//        Float_t      fBy;           //Y intercept at the vertex
//        Float_t      fMeanCharge;   //Mean charge deposition of all hits of this track
//        Float_t      fXfirst;       //X coordinate of the first point
//        Float_t      fXlast;        //X coordinate of the last point
//        Float_t      fYfirst;       //Y coordinate of the first point
//        Float_t      fYlast;        //Y coordinate of the last point
//        Float_t      fZfirst;       //Z coordinate of the first point
//        Float_t      fZlast;        //Z coordinate of the last point
//        Float_t      fCharge;       //Charge of this track
//        Float_t      fVertex[3];    //Track vertex position
//        Int_t        fNpoint;       //Number of points for this track
//        Short_t      fValid;        //Validity criterion
//
//   An example of a batch program to use the Event/Track classes is given
//   in this directory: MainEvent.
//   Look also in the same directory at the following macros:
//     - eventa.C  an example how to read the tree
//     - eventb.C  how to read events conditionally
//
//   During the processing of the event (optionally) also a large number
//   of histograms can be filled. The creation and handling of the
//   histograms is taken care of by the HistogramManager class.
//
////////////////////////////////////////////////////////////////////////

#include "TRandom.h"
#include "TDirectory.h"

#include "Event.h"

ClassImp(EventHeader)
ClassImp(Event)
ClassImp(Track)
ClassImp(HistogramManager)

TClonesArray *Event::fgTracks = 0;
TH1F *Event::fgHist = 0;

//______________________________________________________________________________
Event::Event()
{
   // Create an Event object.
   // When the constructor is invoked for the first time, the class static
   // variable fgTracks is 0 and the TClonesArray fgTracks is created.

   if (!fgTracks) fgTracks = new TClonesArray("Track", 1000);
   fTracks = fgTracks;
   fHighPt = new TRefArray;
   fMuons  = new TRefArray;
   fNtrack = 0;
   fH      = 0;
   Int_t i0,i1;
   for (i0 = 0; i0 < 4; i0++) {
      for (i1 = 0; i1 < 4; i1++) {
         fMatrix[i0][i1] = 0.0;
      }
   }
   for (i0 = 0; i0 <10; i0++) fMeasures[i0] = 0;
   fClosestDistance = 0;
   fEventName = 0;
}

//______________________________________________________________________________
Event::~Event()
{
   Clear();
   if (fH == fgHist) fgHist = 0;
   delete fH; fH = 0;
   delete fHighPt; fHighPt = 0;
   delete fMuons;  fMuons = 0;
   delete [] fClosestDistance;
   if (fEventName) delete [] fEventName;
}

//______________________________________________________________________________
void Event::Build(Int_t ev, Int_t arg5, Float_t ptmin) {
  char etype[20];
  Float_t sigmat, sigmas;
  gRandom->Rannor(sigmat,sigmas);
  Int_t ntrack   = Int_t(arg5 +arg5*sigmat/120.);
  Float_t random = gRandom->Rndm(1);

  Clear();
  fHighPt->Delete();
  fMuons->Delete();

  Int_t nch = 15;
  if (ev > 100)   nch += 3;
  if (ev > 10000) nch += 3;
  if (fEventName) delete [] fEventName;
  fEventName = new char[nch];
  sprintf(fEventName,"Event%d_Run%d",ev,200);
  sprintf(etype,"type%d",ev%5);
  SetType(etype);
  SetHeader(ev, 200, 960312, random);
  SetNseg(Int_t(10*ntrack+20*sigmas));
  SetNvertex(Int_t(1+20*gRandom->Rndm()));
  SetFlag(UInt_t(random+0.5));
  SetTemperature(random+20.);

  for(UChar_t m = 0; m < 10; m++) {
     SetMeasure(m, Int_t(gRandom->Gaus(m,m+1)));
  }
  for(UChar_t i0 = 0; i0 < 4; i0++) {
    for(UChar_t i1 = 0; i1 < 4; i1++) {
       SetMatrix(i0,i1,gRandom->Gaus(i0*i1,1));
    }
  }

   //  Create and Fill the Track objects
  for (Int_t t = 0; t < ntrack; t++) AddTrack(random,ptmin);
}

//______________________________________________________________________________
Track *Event::AddTrack(Float_t random, Float_t ptmin)
{
   // Add a new track to the list of tracks for this event.
   // To avoid calling the very time consuming operator new for each track,
   // the standard but not well know C++ operator "new with placement"
   // is called. If tracks[i] is 0, a new Track object will be created
   // otherwise the previous Track[i] will be overwritten.

   TClonesArray &tracks = *fTracks;
   Track *track = new(tracks[fNtrack++]) Track(random);
   //Save reference to last Track in the collection of Tracks
   fLastTrack = track;
   //Save reference in fHighPt if track is a high Pt track
   if (track->GetPt() > ptmin)   fHighPt->Add(track);
   //Save reference in fMuons if track is a muon candidate
   if (track->GetMass2() < 0.11) fMuons->Add(track);
   return track;
}

//______________________________________________________________________________
void Event::Clear(Option_t *option)
{
   fTracks->Clear(option);
   fHighPt->Delete();
   fMuons->Delete();
}

//______________________________________________________________________________
void Event::Reset(Option_t *option)
{
// Static function to reset all static objects for this event
//   fgTracks->Delete(option);

   delete fgTracks; fgTracks = 0;
   fgHist   = 0;
}

//______________________________________________________________________________
void Event::SetHeader(Int_t i, Int_t run, Int_t date, Float_t random)
{
   fNtrack = 0;
   fEvtHdr.Set(i, run, date);
   if (!fgHist) fgHist = new TH1F("hstat","Event Histogram",100,0,1);
   fH = fgHist;
   fH->Fill(random);
}

//______________________________________________________________________________
void Event::SetMeasure(UChar_t which, Int_t what) {
   if (which<10) fMeasures[which] = what;
}

//______________________________________________________________________________
void Event::SetRandomVertex() {
   // This delete is to test the relocation of variable length array
   if (fClosestDistance) delete [] fClosestDistance;
   if (!fNvertex) {
      fClosestDistance = 0;
      return;
   }
   fClosestDistance = new Float_t[fNvertex];
   for (Int_t k = 0; k < fNvertex; k++ ) {
      fClosestDistance[k] = gRandom->Gaus(1,1);
   }
}

//______________________________________________________________________________
Track::Track(Float_t random) : TObject()
{
   // Create a track object.
   // Note that in this example, data members do not have any physical meaning.

   Float_t a,b,px,py;
   gRandom->Rannor(px,py);
   fPx = px;
   fPy = py;
   fPz = TMath::Sqrt(px*px+py*py);
   fRandom = 1000*random;
   if (fRandom < 10) fMass2 = 0.106;
   else if (fRandom < 100) fMass2 = 0.8;
   else if (fRandom < 500) fMass2 = 4.5;
   else if (fRandom < 900) fMass2 = 8.9;
   else  fMass2 = 9.8;
   gRandom->Rannor(a,b);
   fBx = 0.1*a;
   fBy = 0.1*b;
   fMeanCharge = 0.01*gRandom->Rndm(1);
   gRandom->Rannor(a,b);
   fXfirst = a*10;
   fXlast  = b*10;
   gRandom->Rannor(a,b);
   fYfirst = a*12;
   fYlast  = b*16;
   gRandom->Rannor(a,b);
   fZfirst = 50 + 5*a;
   fZlast  = 200 + 10*b;
   fCharge = Float_t(Int_t(3*gRandom->Rndm(1)) - 1);
   fVertex[0] = gRandom->Gaus(0,0.1);
   fVertex[1] = gRandom->Gaus(0,0.2);
   fVertex[2] = gRandom->Gaus(0,10);
   fNpoint = Int_t(60+10*gRandom->Rndm(1));
   fValid  = Int_t(0.6+gRandom->Rndm(1));
}

//______________________________________________________________________________
HistogramManager::HistogramManager(TDirectory *dir)
{
   // Create histogram manager object. Histograms will be created
   // in the "dir" directory.

   // Save current directory and cd to "dir".
   TDirectory *saved = gDirectory;
   dir->cd();

   fNtrack      = new TH1F("hNtrack",    "Ntrack",100,575,625);
   fNseg        = new TH1F("hNseg",      "Nseg",100,5800,6200);
   fTemperature = new TH1F("hTemperature","Temperature",100,19.5,20.5);
   fPx          = new TH1F("hPx",        "Px",100,-4,4);
   fPy          = new TH1F("hPy",        "Py",100,-4,4);
   fPz          = new TH1F("hPz",        "Pz",100,0,5);
   fRandom      = new TH1F("hRandom",    "Random",100,0,1000);
   fMass2       = new TH1F("hMass2",     "Mass2",100,0,12);
   fBx          = new TH1F("hBx",        "Bx",100,-0.5,0.5);
   fBy          = new TH1F("hBy",        "By",100,-0.5,0.5);
   fMeanCharge  = new TH1F("hMeanCharge","MeanCharge",100,0,0.01);
   fXfirst      = new TH1F("hXfirst",    "Xfirst",100,-40,40);
   fXlast       = new TH1F("hXlast",     "Xlast",100,-40,40);
   fYfirst      = new TH1F("hYfirst",    "Yfirst",100,-40,40);
   fYlast       = new TH1F("hYlast",     "Ylast",100,-40,40);
   fZfirst      = new TH1F("hZfirst",    "Zfirst",100,0,80);
   fZlast       = new TH1F("hZlast",     "Zlast",100,0,250);
   fCharge      = new TH1F("hCharge",    "Charge",100,-1.5,1.5);
   fNpoint      = new TH1F("hNpoint",    "Npoint",100,50,80);
   fValid       = new TH1F("hValid",     "Valid",100,0,1.2);

   // cd back to original directory
   saved->cd();
}

//______________________________________________________________________________
HistogramManager::~HistogramManager()
{
   // Clean up all histograms.

   // Nothing to do. Histograms will be deleted when the directory
   // in which tey are stored is closed.
}

//______________________________________________________________________________
void HistogramManager::Hfill(Event *event)
{
   // Fill histograms.

   fNtrack->Fill(event->GetNtrack());
   fNseg->Fill(event->GetNseg());
   fTemperature->Fill(event->GetTemperature());

   for (Int_t itrack = 0; itrack < event->GetNtrack(); itrack++) {
      Track *track = (Track*)event->GetTracks()->UncheckedAt(itrack);
      fPx->Fill(track->GetPx());
      fPy->Fill(track->GetPy());
      fPz->Fill(track->GetPz());
      fRandom->Fill(track->GetRandom());
      fMass2->Fill(track->GetMass2());
      fBx->Fill(track->GetBx());
      fBy->Fill(track->GetBy());
      fMeanCharge->Fill(track->GetMeanCharge());
      fXfirst->Fill(track->GetXfirst());
      fXlast->Fill(track->GetXlast());
      fYfirst->Fill(track->GetYfirst());
      fYlast->Fill(track->GetYlast());
      fZfirst->Fill(track->GetZfirst());
      fZlast->Fill(track->GetZlast());
      fCharge->Fill(track->GetCharge());
      fNpoint->Fill(track->GetNpoint());
      fValid->Fill(track->GetValid());
   }
}
<commit_msg>In Event::Build, show an example of call to TRef::GetObjectCount and SetObjectCount. For an explanation of these two calls, see the explanation in class TRef.<commit_after>// @(#)root/test:$Name:  $:$Id: Event.cxx,v 1.14 2001/11/22 15:12:25 brun Exp $
// Author: Rene Brun   19/08/96

////////////////////////////////////////////////////////////////////////
//
//                       Event and Track classes
//                       =======================
//
//  The Event class is a naive/simple example of an event structure.
//     public:
//        char           fType[20];
//        Int_t          fNtrack;
//        Int_t          fNseg;
//        Int_t          fNvertex;
//        UInt_t         fFlag;
//        Float_t        fTemperature;
//        Int_t          fMeasures[10];
//        Float_t        fMatrix[4][4];
//        Float_t       *fClosestDistance; //[fNvertex] indexed array!
//        EventHeader    fEvtHdr;
//        TClonesArray  *fTracks;
//        TRefArray     *fHighPt;            //array of High Pt tracks only
//        TRefArray     *fMuons;             //array of Muon tracks only
//        TRef           fLastTrack;         //pointer to last track
//        TRef           fHistoWeb;          //EXEC:GetHistoWeb reference to an histogram in a TWebFile
//        TH1F          *fH;
//
//   The EventHeader class has 3 data members (integers):
//     public:
//        Int_t          fEvtNum;
//        Int_t          fRun;
//        Int_t          fDate;
//
//
//   The Event data member fTracks is a pointer to a TClonesArray.
//   It is an array of a variable number of tracks per event.
//   Each element of the array is an object of class Track with the members:
//     private:
//        Float_t      fPx;           //X component of the momentum
//        Float_t      fPy;           //Y component of the momentum
//        Float_t      fPz;           //Z component of the momentum
//        Float_t      fRandom;       //A random track quantity
//        Float_t      fMass2;        //The mass square of this particle
//        Float_t      fBx;           //X intercept at the vertex
//        Float_t      fBy;           //Y intercept at the vertex
//        Float_t      fMeanCharge;   //Mean charge deposition of all hits of this track
//        Float_t      fXfirst;       //X coordinate of the first point
//        Float_t      fXlast;        //X coordinate of the last point
//        Float_t      fYfirst;       //Y coordinate of the first point
//        Float_t      fYlast;        //Y coordinate of the last point
//        Float_t      fZfirst;       //Z coordinate of the first point
//        Float_t      fZlast;        //Z coordinate of the last point
//        Float_t      fCharge;       //Charge of this track
//        Float_t      fVertex[3];    //Track vertex position
//        Int_t        fNpoint;       //Number of points for this track
//        Short_t      fValid;        //Validity criterion
//
//   An example of a batch program to use the Event/Track classes is given
//   in this directory: MainEvent.
//   Look also in the same directory at the following macros:
//     - eventa.C  an example how to read the tree
//     - eventb.C  how to read events conditionally
//
//   During the processing of the event (optionally) also a large number
//   of histograms can be filled. The creation and handling of the
//   histograms is taken care of by the HistogramManager class.
//
////////////////////////////////////////////////////////////////////////

#include "TRandom.h"
#include "TDirectory.h"

#include "Event.h"

ClassImp(EventHeader)
ClassImp(Event)
ClassImp(Track)
ClassImp(HistogramManager)

TClonesArray *Event::fgTracks = 0;
TH1F *Event::fgHist = 0;

//______________________________________________________________________________
Event::Event()
{
   // Create an Event object.
   // When the constructor is invoked for the first time, the class static
   // variable fgTracks is 0 and the TClonesArray fgTracks is created.

   if (!fgTracks) fgTracks = new TClonesArray("Track", 1000);
   fTracks = fgTracks;
   fHighPt = new TRefArray;
   fMuons  = new TRefArray;
   fNtrack = 0;
   fH      = 0;
   Int_t i0,i1;
   for (i0 = 0; i0 < 4; i0++) {
      for (i1 = 0; i1 < 4; i1++) {
         fMatrix[i0][i1] = 0.0;
      }
   }
   for (i0 = 0; i0 <10; i0++) fMeasures[i0] = 0;
   fClosestDistance = 0;
   fEventName = 0;
   fWebHistogram.SetAction(this);
}

//______________________________________________________________________________
Event::~Event()
{
   Clear();
   if (fH == fgHist) fgHist = 0;
   delete fH; fH = 0;
   delete fHighPt; fHighPt = 0;
   delete fMuons;  fMuons = 0;
   delete [] fClosestDistance;
   if (fEventName) delete [] fEventName;
}

//______________________________________________________________________________
void Event::Build(Int_t ev, Int_t arg5, Float_t ptmin) {
  char etype[20];
  Float_t sigmat, sigmas;
  gRandom->Rannor(sigmat,sigmas);
  Int_t ntrack   = Int_t(arg5 +arg5*sigmat/120.);
  Float_t random = gRandom->Rndm(1);

  //Save current Object count
  Int_t ObjectNumber = TRef::GetObjectCount();
  Clear();
  fHighPt->Delete();
  fMuons->Delete();

  Int_t nch = 15;
  if (ev > 100)   nch += 3;
  if (ev > 10000) nch += 3;
  if (fEventName) delete [] fEventName;
  fEventName = new char[nch];
  sprintf(fEventName,"Event%d_Run%d",ev,200);
  sprintf(etype,"type%d",ev%5);
  SetType(etype);
  SetHeader(ev, 200, 960312, random);
  SetNseg(Int_t(10*ntrack+20*sigmas));
  SetNvertex(Int_t(1+20*gRandom->Rndm()));
  SetFlag(UInt_t(random+0.5));
  SetTemperature(random+20.);

  for(UChar_t m = 0; m < 10; m++) {
     SetMeasure(m, Int_t(gRandom->Gaus(m,m+1)));
  }
  for(UChar_t i0 = 0; i0 < 4; i0++) {
    for(UChar_t i1 = 0; i1 < 4; i1++) {
       SetMatrix(i0,i1,gRandom->Gaus(i0*i1,1));
    }
  }

   //  Create and Fill the Track objects
  for (Int_t t = 0; t < ntrack; t++) AddTrack(random,ptmin);

  //Restore Object count
  //To save space in the table keeping track of all referenced objects
  //we assume that our events do not address each other. We reset the
  //object count to what it was at the beginning of the event.
  TRef::SetObjectCount(ObjectNumber);
}

//______________________________________________________________________________
Track *Event::AddTrack(Float_t random, Float_t ptmin)
{
   // Add a new track to the list of tracks for this event.
   // To avoid calling the very time consuming operator new for each track,
   // the standard but not well know C++ operator "new with placement"
   // is called. If tracks[i] is 0, a new Track object will be created
   // otherwise the previous Track[i] will be overwritten.

   TClonesArray &tracks = *fTracks;
   Track *track = new(tracks[fNtrack++]) Track(random);
   //Save reference to last Track in the collection of Tracks
   fLastTrack = track;
   //Save reference in fHighPt if track is a high Pt track
   if (track->GetPt() > ptmin)   fHighPt->Add(track);
   //Save reference in fMuons if track is a muon candidate
   if (track->GetMass2() < 0.11) fMuons->Add(track);
   return track;
}

//______________________________________________________________________________
void Event::Clear(Option_t *option)
{
   fTracks->Clear(option);
   fHighPt->Delete();
   fMuons->Delete();
}

//______________________________________________________________________________
void Event::Reset(Option_t *option)
{
// Static function to reset all static objects for this event
//   fgTracks->Delete(option);

   delete fgTracks; fgTracks = 0;
   fgHist   = 0;
}

//______________________________________________________________________________
void Event::SetHeader(Int_t i, Int_t run, Int_t date, Float_t random)
{
   fNtrack = 0;
   fEvtHdr.Set(i, run, date);
   if (!fgHist) fgHist = new TH1F("hstat","Event Histogram",100,0,1);
   fH = fgHist;
   fH->Fill(random);
}

//______________________________________________________________________________
void Event::SetMeasure(UChar_t which, Int_t what) {
   if (which<10) fMeasures[which] = what;
}

//______________________________________________________________________________
void Event::SetRandomVertex() {
   // This delete is to test the relocation of variable length array
   if (fClosestDistance) delete [] fClosestDistance;
   if (!fNvertex) {
      fClosestDistance = 0;
      return;
   }
   fClosestDistance = new Float_t[fNvertex];
   for (Int_t k = 0; k < fNvertex; k++ ) {
      fClosestDistance[k] = gRandom->Gaus(1,1);
   }
}

//______________________________________________________________________________
Track::Track(Float_t random) : TObject()
{
   // Create a track object.
   // Note that in this example, data members do not have any physical meaning.

   Float_t a,b,px,py;
   gRandom->Rannor(px,py);
   fPx = px;
   fPy = py;
   fPz = TMath::Sqrt(px*px+py*py);
   fRandom = 1000*random;
   if (fRandom < 10) fMass2 = 0.106;
   else if (fRandom < 100) fMass2 = 0.8;
   else if (fRandom < 500) fMass2 = 4.5;
   else if (fRandom < 900) fMass2 = 8.9;
   else  fMass2 = 9.8;
   gRandom->Rannor(a,b);
   fBx = 0.1*a;
   fBy = 0.1*b;
   fMeanCharge = 0.01*gRandom->Rndm(1);
   gRandom->Rannor(a,b);
   fXfirst = a*10;
   fXlast  = b*10;
   gRandom->Rannor(a,b);
   fYfirst = a*12;
   fYlast  = b*16;
   gRandom->Rannor(a,b);
   fZfirst = 50 + 5*a;
   fZlast  = 200 + 10*b;
   fCharge = Float_t(Int_t(3*gRandom->Rndm(1)) - 1);
   fVertex[0] = gRandom->Gaus(0,0.1);
   fVertex[1] = gRandom->Gaus(0,0.2);
   fVertex[2] = gRandom->Gaus(0,10);
   fNpoint = Int_t(60+10*gRandom->Rndm(1));
   fValid  = Int_t(0.6+gRandom->Rndm(1));
}

//______________________________________________________________________________
HistogramManager::HistogramManager(TDirectory *dir)
{
   // Create histogram manager object. Histograms will be created
   // in the "dir" directory.

   // Save current directory and cd to "dir".
   TDirectory *saved = gDirectory;
   dir->cd();

   fNtrack      = new TH1F("hNtrack",    "Ntrack",100,575,625);
   fNseg        = new TH1F("hNseg",      "Nseg",100,5800,6200);
   fTemperature = new TH1F("hTemperature","Temperature",100,19.5,20.5);
   fPx          = new TH1F("hPx",        "Px",100,-4,4);
   fPy          = new TH1F("hPy",        "Py",100,-4,4);
   fPz          = new TH1F("hPz",        "Pz",100,0,5);
   fRandom      = new TH1F("hRandom",    "Random",100,0,1000);
   fMass2       = new TH1F("hMass2",     "Mass2",100,0,12);
   fBx          = new TH1F("hBx",        "Bx",100,-0.5,0.5);
   fBy          = new TH1F("hBy",        "By",100,-0.5,0.5);
   fMeanCharge  = new TH1F("hMeanCharge","MeanCharge",100,0,0.01);
   fXfirst      = new TH1F("hXfirst",    "Xfirst",100,-40,40);
   fXlast       = new TH1F("hXlast",     "Xlast",100,-40,40);
   fYfirst      = new TH1F("hYfirst",    "Yfirst",100,-40,40);
   fYlast       = new TH1F("hYlast",     "Ylast",100,-40,40);
   fZfirst      = new TH1F("hZfirst",    "Zfirst",100,0,80);
   fZlast       = new TH1F("hZlast",     "Zlast",100,0,250);
   fCharge      = new TH1F("hCharge",    "Charge",100,-1.5,1.5);
   fNpoint      = new TH1F("hNpoint",    "Npoint",100,50,80);
   fValid       = new TH1F("hValid",     "Valid",100,0,1.2);

   // cd back to original directory
   saved->cd();
}

//______________________________________________________________________________
HistogramManager::~HistogramManager()
{
   // Clean up all histograms.

   // Nothing to do. Histograms will be deleted when the directory
   // in which tey are stored is closed.
}

//______________________________________________________________________________
void HistogramManager::Hfill(Event *event)
{
   // Fill histograms.

   fNtrack->Fill(event->GetNtrack());
   fNseg->Fill(event->GetNseg());
   fTemperature->Fill(event->GetTemperature());

   for (Int_t itrack = 0; itrack < event->GetNtrack(); itrack++) {
      Track *track = (Track*)event->GetTracks()->UncheckedAt(itrack);
      fPx->Fill(track->GetPx());
      fPy->Fill(track->GetPy());
      fPz->Fill(track->GetPz());
      fRandom->Fill(track->GetRandom());
      fMass2->Fill(track->GetMass2());
      fBx->Fill(track->GetBx());
      fBy->Fill(track->GetBy());
      fMeanCharge->Fill(track->GetMeanCharge());
      fXfirst->Fill(track->GetXfirst());
      fXlast->Fill(track->GetXlast());
      fYfirst->Fill(track->GetYfirst());
      fYlast->Fill(track->GetYlast());
      fZfirst->Fill(track->GetZfirst());
      fZlast->Fill(track->GetZlast());
      fCharge->Fill(track->GetCharge());
      fNpoint->Fill(track->GetNpoint());
      fValid->Fill(track->GetValid());
   }
}
<|endoftext|>


<commit_before>#include <unit_test/unit_test.h>

#include <drivers/drv_hrt.h>
#include <geo/geo.h>
#include <px4iofirmware/px4io.h>
#include <systemlib/err.h>
#include <systemlib/mixer/mixer.h>

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

class AutoDeclinationTest : public UnitTest
{
public:
	virtual bool run_tests();

private:
	bool autodeclination_check();
};

bool AutoDeclinationTest::autodeclination_check()
{
	ut_assert("declination differs more than 1 degree", get_mag_declination(47.0, 8.0) - 1.6f < 0.5f);

	return true;
}

bool AutoDeclinationTest::run_tests()
{
	ut_run_test(autodeclination_check);

	return (_tests_failed == 0);
}

ut_declare_test_c(test_autodeclination, AutoDeclinationTest)
<commit_msg>test_autodeclination: Add world endpoints to test.<commit_after>#include <unit_test/unit_test.h>

#include <drivers/drv_hrt.h>
#include <geo/geo.h>
#include <px4iofirmware/px4io.h>
#include <systemlib/err.h>
#include <systemlib/mixer/mixer.h>

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

class AutoDeclinationTest : public UnitTest
{
public:
	virtual bool run_tests();

private:
	bool autodeclination_check();
};

bool AutoDeclinationTest::autodeclination_check()
{
	ut_assert("declination differs more than 0.1 degrees", get_mag_declination(47.0, 8.0) - 1.6f < 0.1f);
	// Test world endpoints
	ut_assert("declination differs more than 0.1 degrees", get_mag_declination(-90.0, 180.0) - 47.0f < 0.1f);
	ut_assert("declination differs more than 0.1 degrees", get_mag_declination(-90.0, -180.0) - 47.0f < 0.1f);
	ut_assert("declination differs more than 0.1 degrees", get_mag_declination(90.0, -180.0) - 3.0f < 0.1f);
	ut_assert("declination differs more than 0.1 degrees", get_mag_declination(90.0, 180.0) - 3.0f < 0.1f);

	return true;
}

bool AutoDeclinationTest::run_tests()
{
	ut_run_test(autodeclination_check);

	return (_tests_failed == 0);
}

ut_declare_test_c(test_autodeclination, AutoDeclinationTest)
<|endoftext|>