<commit_before>////////////////////////////////////////////////////////////////////////////////
//
//  File:  SpatialDomains.hpp
//
//  For more information, please see: http://www.nektar.info/
//
//  The MIT License
//
//  Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
//  Department of Aeronautics, Imperial College London (UK), and Scientific
//  Computing and Imaging Institute, University of Utah (USA).
//
//  License for the specific language governing rights and limitations under
//  Permission is hereby granted, free of charge, to any person obtaining a
//  copy of this software and associated documentation files (the "Software"),
//  to deal in the Software without restriction, including without limitation
//  the rights to use, copy, modify, merge, publish, distribute, sublicense,
//  and/or sell copies of the Software, and to permit persons to whom the
//  Software is furnished to do so, subject to the following conditions:
//
//  The above copyright notice and this permission notice shall be included
//  in all copies or substantial portions of the Software.
//
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
//  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
//  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
//  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
//  DEALINGS IN THE SOFTWARE.
//
//  Description:
//
//
////////////////////////////////////////////////////////////////////////////////
#ifndef NEKTAR_SPATIALDOMAINS_SPATIALDOMAINS_H
#define NEKTAR_SPATIALDOMAINS_SPATIALDOMAINS_H

#include <StdRegions/StdRegions.hpp>

#include <LibUtilities/Memory/NekMemoryManager.hpp>
#include <LibUtilities/BasicUtils/ErrorUtil.hpp>
#include <LibUtilities/Foundations/Graph.h>

namespace Nektar
{
    /** \brief The namespace associated with the the SpatialDomains library
     * (\ref pageSpatialDomains "SpatialDomains introduction")
     */
    namespace SpatialDomains
    {
        /** \page pageSpatialDomains The SpatialDomains library
         *
         */
        const double kGeomRightAngleTol = 1e-14;

        enum GeomType
        {
            eNoGeomType,
            eRegular,
            eDeformed,
            eMovingRegular,
        };

        enum GeomState
        {
            eNotFilled,
            ePtsFilled
        };

        enum MeshParams
        {
            eFieldExpansionOrder,
            eElementWork,

            // Don't change below here
            SIZE_MeshParams
        };
    }; // end of namespace
}; // end of namespace

#endif //NEKTAR_SPATIALDOMAINS_SPATIALDOMAINS_H

//
// $Log: SpatialDomains.hpp,v $
// Revision 1.4  2007/03/14 21:24:08  sherwin
// Update for working version of MultiRegions up to ExpList1D
//
// Revision 1.3  2006/06/01 15:03:59  kirby
// *** empty log message ***
//
// Revision 1.2  2006/06/01 13:42:26  kirby
// *** empty log message ***
//
// Revision 1.1  2006/05/04 18:59:04  kirby
// *** empty log message ***
//
// Revision 1.4  2006/03/25 00:58:29  jfrazier
// Many changes dealing with fundamental structure and reading/writing.
//
// Revision 1.3  2006/03/13 11:17:03  sherwin
//
// First compiing version of Demos in SpatialDomains and LocalRegions. However they do not currently seem to execute properly
//
// Revision 1.2  2006/03/12 14:20:44  sherwin
//
// First compiling version of SpatialDomains and associated modifications
//
// Revision 1.1  2006/03/12 11:06:40  sherwin
//
// First complete copy of code standard code but still not compile tested
//
// Revision 1.7  2006/03/04 20:26:05  bnelson
// Added comments after #endif.
//
// Revision 1.6  2006/02/19 01:37:34  jfrazier
// Initial attempt at bringing into conformance with the coding standard.  Still more work to be done.  Has not been compiled.
//
//
<commit_msg>Added reference interp.h<commit_after>////////////////////////////////////////////////////////////////////////////////
//
//  File:  SpatialDomains.hpp
//
//  For more information, please see: http://www.nektar.info/
//
//  The MIT License
//
//  Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
//  Department of Aeronautics, Imperial College London (UK), and Scientific
//  Computing and Imaging Institute, University of Utah (USA).
//
//  License for the specific language governing rights and limitations under
//  Permission is hereby granted, free of charge, to any person obtaining a
//  copy of this software and associated documentation files (the "Software"),
//  to deal in the Software without restriction, including without limitation
//  the rights to use, copy, modify, merge, publish, distribute, sublicense,
//  and/or sell copies of the Software, and to permit persons to whom the
//  Software is furnished to do so, subject to the following conditions:
//
//  The above copyright notice and this permission notice shall be included
//  in all copies or substantial portions of the Software.
//
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
//  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
//  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
//  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
//  DEALINGS IN THE SOFTWARE.
//
//  Description:
//
//
////////////////////////////////////////////////////////////////////////////////
#ifndef NEKTAR_SPATIALDOMAINS_SPATIALDOMAINS_H
#define NEKTAR_SPATIALDOMAINS_SPATIALDOMAINS_H

#include <StdRegions/StdRegions.hpp>

#include <LibUtilities/Memory/NekMemoryManager.hpp>
#include <LibUtilities/BasicUtils/ErrorUtil.hpp>
#include <LibUtilities/Foundations/Graph.h>

#include <LibUtilities/Foundations/Interp.h>

namespace Nektar
{
    /** \brief The namespace associated with the the SpatialDomains library
     * (\ref pageSpatialDomains "SpatialDomains introduction")
     */
    namespace SpatialDomains
    {
        /** \page pageSpatialDomains The SpatialDomains library
         *
         */
        const double kGeomRightAngleTol = 1e-14;

        enum GeomType
        {
            eNoGeomType,
            eRegular,
            eDeformed,
            eMovingRegular,
        };

        enum GeomState
        {
            eNotFilled,
            ePtsFilled
        };

        enum MeshParams
        {
            eFieldExpansionOrder,
            eElementWork,

            // Don't change below here
            SIZE_MeshParams
        };
    }; // end of namespace
}; // end of namespace

#endif //NEKTAR_SPATIALDOMAINS_SPATIALDOMAINS_H

//
// $Log: SpatialDomains.hpp,v $
// Revision 1.5  2008/06/05 15:06:31  pvos
// Added documentation
//
// Revision 1.4  2007/03/14 21:24:08  sherwin
// Update for working version of MultiRegions up to ExpList1D
//
// Revision 1.3  2006/06/01 15:03:59  kirby
// *** empty log message ***
//
// Revision 1.2  2006/06/01 13:42:26  kirby
// *** empty log message ***
//
// Revision 1.1  2006/05/04 18:59:04  kirby
// *** empty log message ***
//
// Revision 1.4  2006/03/25 00:58:29  jfrazier
// Many changes dealing with fundamental structure and reading/writing.
//
// Revision 1.3  2006/03/13 11:17:03  sherwin
//
// First compiing version of Demos in SpatialDomains and LocalRegions. However they do not currently seem to execute properly
//
// Revision 1.2  2006/03/12 14:20:44  sherwin
//
// First compiling version of SpatialDomains and associated modifications
//
// Revision 1.1  2006/03/12 11:06:40  sherwin
//
// First complete copy of code standard code but still not compile tested
//
// Revision 1.7  2006/03/04 20:26:05  bnelson
// Added comments after #endif.
//
// Revision 1.6  2006/02/19 01:37:34  jfrazier
// Initial attempt at bringing into conformance with the coding standard.  Still more work to be done.  Has not been compiled.
//
//
<|endoftext|>


<commit_before><commit_msg>INTEGRATION: CWS tune01 (1.42.4); FILE MERGED 2003/04/11 13:35:29 mhu 1.42.4.1: #108383# Removed obsolete reference to module inet.<commit_after><|endoftext|>


<commit_before><commit_msg>#90025#: allow to forbid usage of InteractionHandler<commit_after><|endoftext|>


<commit_before><commit_msg>uninitialized pointer => now initialized to 0<commit_after><|endoftext|>


<commit_before>/****************************************************************************
 *
 *   Copyright (c) 2013-2016 PX4 Development Team. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name PX4 nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ****************************************************************************/

/**
 * @file VtolLandDetector.cpp
 * Land detection algorithm for VTOL
 *
 * @author Roman Bapst <bapstroma@gmail.com>
 * @author Julian Oes <julian@oes.ch>
 */

#include <drivers/drv_hrt.h>

#include "VtolLandDetector.h"

namespace land_detector
{

VtolLandDetector::VtolLandDetector()
{
}

void VtolLandDetector::_update_topics()
{
	MulticopterLandDetector::_update_topics();
	_airspeed_sub.update(&_airspeed);
	_vehicle_status_sub.update(&_vehicle_status);
}

bool VtolLandDetector::_get_maybe_landed_state()
{
	// Only trigger in RW mode
	if ((_vehicle_status.timestamp != 0) && _vehicle_status.vehicle_type == vehicle_status_s::VEHICLE_TYPE_FIXED_WING) {
		return false;
	}

	return MulticopterLandDetector::_get_maybe_landed_state();
}

bool VtolLandDetector::_get_landed_state()
{
	// Only trigger in RW mode
	if ((_vehicle_status.timestamp != 0) && _vehicle_status.vehicle_type == vehicle_status_s::VEHICLE_TYPE_FIXED_WING) {
		return false;
	}

	// this is returned from the mutlicopter land detector
	bool landed = MulticopterLandDetector::_get_landed_state();

	// for vtol we additionally consider airspeed
	if (hrt_elapsed_time(&_airspeed.timestamp) < 500 * 1000 && _airspeed.confidence > 0.99f
	    && PX4_ISFINITE(_airspeed.indicated_airspeed_m_s)) {

		_airspeed_filtered = 0.95f * _airspeed_filtered + 0.05f * _airspeed.indicated_airspeed_m_s;

	} else {
		// if airspeed does not update, set it to zero and rely on multicopter land detector
		_airspeed_filtered = 0.0f;
	}

	// only consider airspeed if we have been in air before to avoid false
	// detections in the case of wind on the ground
	if (_was_in_air && (_airspeed_filtered > _param_lndfw_airspd_max.get())) {
		landed = false;
	}

	_was_in_air = !landed;

	return landed;
}

} // namespace land_detector
<commit_msg>VTOL land detector: trigger land detector in fixed-wing mode if disarmed.<commit_after>/****************************************************************************
 *
 *   Copyright (c) 2013-2016 PX4 Development Team. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name PX4 nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ****************************************************************************/

/**
 * @file VtolLandDetector.cpp
 * Land detection algorithm for VTOL
 *
 * @author Roman Bapst <bapstroma@gmail.com>
 * @author Julian Oes <julian@oes.ch>
 */

#include <drivers/drv_hrt.h>

#include "VtolLandDetector.h"

namespace land_detector
{

VtolLandDetector::VtolLandDetector()
{
}

void VtolLandDetector::_update_topics()
{
	MulticopterLandDetector::_update_topics();
	_airspeed_sub.update(&_airspeed);
	_vehicle_status_sub.update(&_vehicle_status);
}

bool VtolLandDetector::_get_maybe_landed_state()
{
	// If in Fixed-wing mode, only trigger if disarmed
	if ((_vehicle_status.timestamp != 0) && _vehicle_status.vehicle_type == vehicle_status_s::VEHICLE_TYPE_FIXED_WING) {
		return !_actuator_armed.armed;
	}

	return MulticopterLandDetector::_get_maybe_landed_state();
}

bool VtolLandDetector::_get_landed_state()
{
	// If in Fixed-wing mode, only trigger if disarmed
	if ((_vehicle_status.timestamp != 0) && _vehicle_status.vehicle_type == vehicle_status_s::VEHICLE_TYPE_FIXED_WING) {
		return !_actuator_armed.armed;
	}

	// this is returned from the mutlicopter land detector
	bool landed = MulticopterLandDetector::_get_landed_state();

	// for vtol we additionally consider airspeed
	if (hrt_elapsed_time(&_airspeed.timestamp) < 500 * 1000 && _airspeed.confidence > 0.99f
	    && PX4_ISFINITE(_airspeed.indicated_airspeed_m_s)) {

		_airspeed_filtered = 0.95f * _airspeed_filtered + 0.05f * _airspeed.indicated_airspeed_m_s;

	} else {
		// if airspeed does not update, set it to zero and rely on multicopter land detector
		_airspeed_filtered = 0.0f;
	}

	// only consider airspeed if we have been in air before to avoid false
	// detections in the case of wind on the ground
	if (_was_in_air && (_airspeed_filtered > _param_lndfw_airspd_max.get())) {
		landed = false;
	}

	_was_in_air = !landed;

	return landed;
}

} // namespace land_detector
<|endoftext|>


<commit_before>
#ifndef AT_MAP_HPP
#define AT_MAP_HPP

#include "atGlobals.h++"
#include "atList.h++"
#include "atItem.h++"
#include "atNotifier.h++"

enum atMapColor
{
    AT_MAP_BLACK,
    AT_MAP_RED
};

enum atMapChildType
{
    AT_MAP_LEFTCHILD,
    AT_MAP_RIGHTCHILD,
    AT_MAP_ROOTNODE
};

struct atMapNode
{
    atMapNode *   leftChild;
    atMapNode *   rightChild;
    atMapNode *   parent;
    int           color;

    atItem *      nodeKey;
    atItem *      nodeValue;
};

class atMap : public atNotifier
{
private:

    atMapNode *   treeRoot;
    int           treeSize;

    atMapNode *       findNode(atMapNode * node, atItem * key);
    void              rebalanceInsert(atMapNode * node);
    void              rebalanceDelete(atMapNode * parent,
                                      int deletedChildType);
    void              deleteNode(atMapNode * node);
    atMapNode *       getInorderSuccessor(atMapNode * node);
    void              rotateLeft(atMapNode * node);
    void              rotateRight(atMapNode * node);
    void              deleteTree(atMapNode * node);
    int               getChildType(atMapNode * node);
    void              fillLists(atMapNode * node, atList * keyList,
                                atList * valueList);

public:

                atMap();
                ~atMap();

    bool        addEntry(atItem * key, atItem * value);
    bool        deleteEntry(atItem * key);
    int         getEntryCount();

    bool        containsKey(atItem * key);
    atItem *    getValue(atItem * key);
    bool        changeValue(atItem * key, atItem * newValue);

    void        clear();

    void        getSortedList(atList * keyList,
                              atList * valueList);
};

#endif
<commit_msg>changeValue function modified so that it returns the old value of the key-value pair if the requested key is present in the map. NULL is returned if the key is not present.<commit_after>
#ifndef AT_MAP_HPP
#define AT_MAP_HPP

#include "atGlobals.h++"
#include "atList.h++"
#include "atItem.h++"
#include "atNotifier.h++"

enum atMapColor
{
    AT_MAP_BLACK,
    AT_MAP_RED
};

enum atMapChildType
{
    AT_MAP_LEFTCHILD,
    AT_MAP_RIGHTCHILD,
    AT_MAP_ROOTNODE
};

struct atMapNode
{
    atMapNode *   leftChild;
    atMapNode *   rightChild;
    atMapNode *   parent;
    int           color;

    atItem *      nodeKey;
    atItem *      nodeValue;
};

class atMap : public atNotifier
{
private:

    atMapNode *   treeRoot;
    int           treeSize;

    atMapNode *       findNode(atMapNode * node, atItem * key);
    void              rebalanceInsert(atMapNode * node);
    void              rebalanceDelete(atMapNode * parent,
                                      int deletedChildType);
    void              deleteNode(atMapNode * node);
    atMapNode *       getInorderSuccessor(atMapNode * node);
    void              rotateLeft(atMapNode * node);
    void              rotateRight(atMapNode * node);
    void              deleteTree(atMapNode * node);
    int               getChildType(atMapNode * node);
    void              fillLists(atMapNode * node, atList * keyList,
                                atList * valueList);

public:

                atMap();
                ~atMap();

    bool        addEntry(atItem * key, atItem * value);
    bool        deleteEntry(atItem * key);
    int         getEntryCount();

    bool        containsKey(atItem * key);
    atItem *    getValue(atItem * key);
    atItem *    changeValue(atItem * key, atItem * newValue);

    void        clear();

    void        getSortedList(atList * keyList,
                              atList * valueList);
};

#endif
<|endoftext|>


<commit_before>#include <iomanip>
#include <iostream>
#include <map>
#include <memory>
#include <set>
#include <sstream>
#include <string>
#include <utility>
#include <uv.h>

#include "../helper/common.h"
#include "../log.h"
#include "../message.h"
#include "directory_record.h"
#include "polling_iterator.h"

using std::dec;
using std::endl;
using std::hex;
using std::move;
using std::ostream;
using std::ostringstream;
using std::set;
using std::shared_ptr;
using std::string;

struct FSReq
{
  uv_fs_t req{};

  FSReq() = default;
  FSReq(const FSReq &) = delete;
  FSReq(FSReq &&) = delete;
  ~FSReq() { uv_fs_req_cleanup(&req); }

  FSReq &operator=(const FSReq &) = delete;
  FSReq &operator=(FSReq &&) = delete;
};

ostream &operator<<(ostream &out, const uv_timespec_t &ts)
{
  return out << ts.tv_sec << "s " << ts.tv_nsec << "ns";
}

ostream &operator<<(ostream &out, const uv_stat_t &stat)
{
  out << "[ino=" << stat.st_ino << " size=" << stat.st_size << " mode=" << hex << stat.st_mode << dec << " (";
  if ((stat.st_mode & S_IFDIR) == S_IFDIR) out << " DIR";
  if ((stat.st_mode & S_IFREG) == S_IFREG) out << " REG";
  if ((stat.st_mode & S_IFLNK) == S_IFLNK) out << " LNK";
  out << " ) atim=" << stat.st_atim << " mtim=" << stat.st_mtim << " birthtim=" << stat.st_birthtim << "]";
  return out;
}

ostream &operator<<(ostream &out, const FSReq &r)
{
  if (r.req.result < 0) {
    return out << "[" << uv_strerror(static_cast<int>(r.req.result)) << "]";
  }

  return out << r.req.statbuf;
}

inline bool ts_not_equal(const uv_timespec_t &left, const uv_timespec_t &right)
{
  return left.tv_sec != right.tv_sec || left.tv_nsec != right.tv_nsec;
}

inline EntryKind kind_from_stat(const uv_stat_t &st)
{
  if ((st.st_mode & S_IFDIR) == S_IFDIR) return KIND_DIRECTORY;
  if ((st.st_mode & S_IFREG) == S_IFREG) return KIND_FILE;
  return KIND_UNKNOWN;
}

DirectoryRecord::DirectoryRecord(string &&prefix) :
  parent{nullptr},
  name{move(prefix)},
  populated{false},
  was_present{false}
{
  //
}

string DirectoryRecord::path() const
{
  return parent == nullptr ? name : path_join(parent->path(), name);
}

void DirectoryRecord::scan(BoundPollingIterator *it)
{
  FSReq scan_req;
  set<Entry> scanned_entries;

  string dir = path();
  int scan_err = uv_fs_scandir(nullptr, &scan_req.req, dir.c_str(), 0, nullptr);
  if (scan_err < 0) {
    if (scan_err == UV_ENOENT || scan_err == UV_ENOTDIR || scan_err == UV_EACCES) {
      if (was_present) {
        it->get_buffer().deleted(move(dir), KIND_DIRECTORY);
        was_present = false;
      }
    } else {
      ostringstream msg;
      msg << "Unable to scan directory " << dir << ": " << uv_strerror(scan_err);
      it->get_buffer().error(msg.str(), false);
    }

    return;
  }

  if (!was_present) {
    it->get_buffer().created(string(dir), KIND_DIRECTORY);
    was_present = true;
  }

  uv_dirent_t dirent{};
  int next_err = uv_fs_scandir_next(&scan_req.req, &dirent);
  while (next_err == 0) {
    string entry_name(dirent.name);

    EntryKind entry_kind = KIND_UNKNOWN;
    if (dirent.type == UV_DIRENT_FILE) entry_kind = KIND_FILE;
    if (dirent.type == UV_DIRENT_DIR) entry_kind = KIND_DIRECTORY;

    it->push_entry(string(entry_name), entry_kind);
    if (populated) scanned_entries.emplace(move(entry_name), entry_kind);

    next_err = uv_fs_scandir_next(&scan_req.req, &dirent);
  }

  if (next_err != UV_EOF) {
    ostringstream msg;
    msg << "Unable to list entries in directory " << dir << ": " << uv_strerror(next_err);

    it->get_buffer().error(msg.str(), false);
  } else {
    // Report entries that were present the last time we scanned this directory, but aren't included in this
    // scan.
    auto previous = entries.begin();
    while (previous != entries.end()) {
      const string &previous_entry_name = previous->first;
      const string previous_entry_path(path_join(dir, previous_entry_name));
      EntryKind previous_entry_kind = kind_from_stat(previous->second);
      Entry previous_entry(previous_entry_name, previous_entry_kind);
      Entry unknown_entry(previous_entry_name, KIND_UNKNOWN);

      if (scanned_entries.count(previous_entry) == 0 && scanned_entries.count(unknown_entry) == 0) {
        entry_deleted(it, previous_entry_path, previous_entry_kind);
        auto former = previous;
        ++previous;

        subdirectories.erase(previous_entry_name);
        entries.erase(former);
      } else {
        ++previous;
      }
    }
  }
}

void DirectoryRecord::entry(BoundPollingIterator *it,
  const string &entry_name,
  const string &entry_path,
  EntryKind scan_kind)
{
  FSReq lstat_req;
  EntryKind previous_kind = scan_kind;
  EntryKind current_kind = scan_kind;

  int lstat_err = uv_fs_lstat(nullptr, &lstat_req.req, entry_path.c_str(), nullptr);
  if (lstat_err != 0 && lstat_err != UV_ENOENT && lstat_err != UV_EACCES) {
    ostringstream msg;
    msg << "Unable to stat " << entry_path << ": " << uv_strerror(lstat_err);
    it->get_buffer().error(msg.str(), false);
  }

  auto previous = entries.find(entry_name);

  bool existed_before = previous != entries.end();
  bool exists_now = lstat_err == 0;

  if (existed_before) previous_kind = kind_from_stat(previous->second);
  if (exists_now) current_kind = kind_from_stat(lstat_req.req.statbuf);

  if (existed_before && exists_now) {
    // Modification or no change
    uv_stat_t &previous_stat = previous->second;
    uv_stat_t &current_stat = lstat_req.req.statbuf;

    // TODO consider modifications to mode or ownership bits?
    if (kinds_are_different(previous_kind, current_kind) || previous_stat.st_ino != current_stat.st_ino) {
      entry_deleted(it, entry_path, previous_kind);
      entry_created(it, entry_path, current_kind);
    } else if (previous_stat.st_mode != current_stat.st_mode || previous_stat.st_size != current_stat.st_size
      || ts_not_equal(previous_stat.st_mtim, current_stat.st_mtim)
      || ts_not_equal(previous_stat.st_ctim, current_stat.st_ctim)) {
      entry_modified(it, entry_path, current_kind);
    }

  } else if (existed_before && !exists_now) {
    // Deletion

    entry_deleted(it, entry_path, previous_kind);

  } else if (!existed_before && exists_now) {
    // Creation

    if (kinds_are_different(scan_kind, current_kind)) {
      // Entry was created as a file, deleted, then recreated as a directory between scan() and entry()
      // (or vice versa)
      entry_created(it, entry_path, scan_kind);
      entry_deleted(it, entry_path, scan_kind);
    }
    entry_created(it, entry_path, current_kind);

  } else if (!existed_before && !exists_now) {
    // Entry was deleted between scan() and entry().
    // Emit a deletion and creation event pair. Note that the kinds will likely both be KIND_UNKNOWN.

    entry_created(it, entry_path, previous_kind);
    entry_deleted(it, entry_path, current_kind);
  }

  // Update entries with the latest stat information
  if (existed_before) entries.erase(previous);
  if (exists_now) entries.emplace(entry_name, lstat_req.req.statbuf);

  // Update subdirectories if this is or was a subdirectory
  auto dir = subdirectories.find(entry_name);
  if (current_kind != KIND_DIRECTORY && current_kind != KIND_UNKNOWN && dir != subdirectories.end()) {
    subdirectories.erase(dir);
  }
  if (current_kind == KIND_DIRECTORY && it->is_recursive()) {
    if (dir == subdirectories.end()) {
      shared_ptr<DirectoryRecord> subdir(new DirectoryRecord(this, string(entry_name)));
      subdirectories.emplace(entry_name, subdir);
      it->push_directory(subdir);
    } else {
      it->push_directory(dir->second);
    }
  }
}

bool DirectoryRecord::all_populated() const
{
  if (!populated) return false;

  for (auto &pair : subdirectories) {
    if (!pair.second->all_populated()) {
      return false;
    }
  }

  return true;
}

size_t DirectoryRecord::count_entries() const
{
  // Start with 1 to count the readdir() on this directory.
  size_t count = 1;
  for (auto &pair : entries) {
    if ((pair.second.st_mode & S_IFDIR) != S_IFDIR) {
      count++;
    }
  }
  for (auto &pair : subdirectories) {
    count += pair.second->count_entries();
  }
  return count;
}

DirectoryRecord::DirectoryRecord(DirectoryRecord *parent, string &&name) :
  parent{parent},
  name(move(name)),
  populated{false}
{
  //
}

void DirectoryRecord::entry_deleted(BoundPollingIterator *it, const string &entry_path, EntryKind kind)
{
  if (!populated) return;

  it->get_buffer().deleted(string(entry_path), kind);
}

void DirectoryRecord::entry_created(BoundPollingIterator *it, const string &entry_path, EntryKind kind)
{
  if (!populated) return;

  it->get_buffer().created(string(entry_path), kind);
}

void DirectoryRecord::entry_modified(BoundPollingIterator *it, const string &entry_path, EntryKind kind)
{
  if (!populated) return;

  it->get_buffer().modified(string(entry_path), kind);
}
<commit_msg>Don't emit events when populating<commit_after>#include <iomanip>
#include <iostream>
#include <map>
#include <memory>
#include <set>
#include <sstream>
#include <string>
#include <utility>
#include <uv.h>

#include "../helper/common.h"
#include "../log.h"
#include "../message.h"
#include "directory_record.h"
#include "polling_iterator.h"

using std::dec;
using std::endl;
using std::hex;
using std::move;
using std::ostream;
using std::ostringstream;
using std::set;
using std::shared_ptr;
using std::string;

struct FSReq
{
  uv_fs_t req{};

  FSReq() = default;
  FSReq(const FSReq &) = delete;
  FSReq(FSReq &&) = delete;
  ~FSReq() { uv_fs_req_cleanup(&req); }

  FSReq &operator=(const FSReq &) = delete;
  FSReq &operator=(FSReq &&) = delete;
};

ostream &operator<<(ostream &out, const uv_timespec_t &ts)
{
  return out << ts.tv_sec << "s " << ts.tv_nsec << "ns";
}

ostream &operator<<(ostream &out, const uv_stat_t &stat)
{
  out << "[ino=" << stat.st_ino << " size=" << stat.st_size << " mode=" << hex << stat.st_mode << dec << " (";
  if ((stat.st_mode & S_IFDIR) == S_IFDIR) out << " DIR";
  if ((stat.st_mode & S_IFREG) == S_IFREG) out << " REG";
  if ((stat.st_mode & S_IFLNK) == S_IFLNK) out << " LNK";
  out << " ) atim=" << stat.st_atim << " mtim=" << stat.st_mtim << " birthtim=" << stat.st_birthtim << "]";
  return out;
}

ostream &operator<<(ostream &out, const FSReq &r)
{
  if (r.req.result < 0) {
    return out << "[" << uv_strerror(static_cast<int>(r.req.result)) << "]";
  }

  return out << r.req.statbuf;
}

inline bool ts_not_equal(const uv_timespec_t &left, const uv_timespec_t &right)
{
  return left.tv_sec != right.tv_sec || left.tv_nsec != right.tv_nsec;
}

inline EntryKind kind_from_stat(const uv_stat_t &st)
{
  if ((st.st_mode & S_IFDIR) == S_IFDIR) return KIND_DIRECTORY;
  if ((st.st_mode & S_IFREG) == S_IFREG) return KIND_FILE;
  return KIND_UNKNOWN;
}

DirectoryRecord::DirectoryRecord(string &&prefix) :
  parent{nullptr},
  name{move(prefix)},
  populated{false},
  was_present{false}
{
  //
}

string DirectoryRecord::path() const
{
  return parent == nullptr ? name : path_join(parent->path(), name);
}

void DirectoryRecord::scan(BoundPollingIterator *it)
{
  FSReq scan_req;
  set<Entry> scanned_entries;

  string dir = path();
  int scan_err = uv_fs_scandir(nullptr, &scan_req.req, dir.c_str(), 0, nullptr);
  if (scan_err < 0) {
    if (scan_err == UV_ENOENT || scan_err == UV_ENOTDIR || scan_err == UV_EACCES) {
      if (was_present) {
        entry_deleted(it, dir, KIND_DIRECTORY);
        was_present = false;
      }
    } else {
      ostringstream msg;
      msg << "Unable to scan directory " << dir << ": " << uv_strerror(scan_err);
      it->get_buffer().error(msg.str(), false);
    }

    return;
  }

  if (!was_present) {
    entry_created(it, dir, KIND_DIRECTORY);
    was_present = true;
  }

  uv_dirent_t dirent{};
  int next_err = uv_fs_scandir_next(&scan_req.req, &dirent);
  while (next_err == 0) {
    string entry_name(dirent.name);

    EntryKind entry_kind = KIND_UNKNOWN;
    if (dirent.type == UV_DIRENT_FILE) entry_kind = KIND_FILE;
    if (dirent.type == UV_DIRENT_DIR) entry_kind = KIND_DIRECTORY;

    it->push_entry(string(entry_name), entry_kind);
    if (populated) scanned_entries.emplace(move(entry_name), entry_kind);

    next_err = uv_fs_scandir_next(&scan_req.req, &dirent);
  }

  if (next_err != UV_EOF) {
    ostringstream msg;
    msg << "Unable to list entries in directory " << dir << ": " << uv_strerror(next_err);

    it->get_buffer().error(msg.str(), false);
  } else {
    // Report entries that were present the last time we scanned this directory, but aren't included in this
    // scan.
    auto previous = entries.begin();
    while (previous != entries.end()) {
      const string &previous_entry_name = previous->first;
      const string previous_entry_path(path_join(dir, previous_entry_name));
      EntryKind previous_entry_kind = kind_from_stat(previous->second);
      Entry previous_entry(previous_entry_name, previous_entry_kind);
      Entry unknown_entry(previous_entry_name, KIND_UNKNOWN);

      if (scanned_entries.count(previous_entry) == 0 && scanned_entries.count(unknown_entry) == 0) {
        entry_deleted(it, previous_entry_path, previous_entry_kind);
        auto former = previous;
        ++previous;

        subdirectories.erase(previous_entry_name);
        entries.erase(former);
      } else {
        ++previous;
      }
    }
  }
}

void DirectoryRecord::entry(BoundPollingIterator *it,
  const string &entry_name,
  const string &entry_path,
  EntryKind scan_kind)
{
  FSReq lstat_req;
  EntryKind previous_kind = scan_kind;
  EntryKind current_kind = scan_kind;

  int lstat_err = uv_fs_lstat(nullptr, &lstat_req.req, entry_path.c_str(), nullptr);
  if (lstat_err != 0 && lstat_err != UV_ENOENT && lstat_err != UV_EACCES) {
    ostringstream msg;
    msg << "Unable to stat " << entry_path << ": " << uv_strerror(lstat_err);
    it->get_buffer().error(msg.str(), false);
  }

  auto previous = entries.find(entry_name);

  bool existed_before = previous != entries.end();
  bool exists_now = lstat_err == 0;

  if (existed_before) previous_kind = kind_from_stat(previous->second);
  if (exists_now) current_kind = kind_from_stat(lstat_req.req.statbuf);

  if (existed_before && exists_now) {
    // Modification or no change
    uv_stat_t &previous_stat = previous->second;
    uv_stat_t &current_stat = lstat_req.req.statbuf;

    // TODO consider modifications to mode or ownership bits?
    if (kinds_are_different(previous_kind, current_kind) || previous_stat.st_ino != current_stat.st_ino) {
      entry_deleted(it, entry_path, previous_kind);
      entry_created(it, entry_path, current_kind);
    } else if (previous_stat.st_mode != current_stat.st_mode || previous_stat.st_size != current_stat.st_size
      || ts_not_equal(previous_stat.st_mtim, current_stat.st_mtim)
      || ts_not_equal(previous_stat.st_ctim, current_stat.st_ctim)) {
      entry_modified(it, entry_path, current_kind);
    }

  } else if (existed_before && !exists_now) {
    // Deletion

    entry_deleted(it, entry_path, previous_kind);

  } else if (!existed_before && exists_now) {
    // Creation

    if (kinds_are_different(scan_kind, current_kind)) {
      // Entry was created as a file, deleted, then recreated as a directory between scan() and entry()
      // (or vice versa)
      entry_created(it, entry_path, scan_kind);
      entry_deleted(it, entry_path, scan_kind);
    }
    entry_created(it, entry_path, current_kind);

  } else if (!existed_before && !exists_now) {
    // Entry was deleted between scan() and entry().
    // Emit a deletion and creation event pair. Note that the kinds will likely both be KIND_UNKNOWN.

    entry_created(it, entry_path, previous_kind);
    entry_deleted(it, entry_path, current_kind);
  }

  // Update entries with the latest stat information
  if (existed_before) entries.erase(previous);
  if (exists_now) entries.emplace(entry_name, lstat_req.req.statbuf);

  // Update subdirectories if this is or was a subdirectory
  auto dir = subdirectories.find(entry_name);
  if (current_kind != KIND_DIRECTORY && current_kind != KIND_UNKNOWN && dir != subdirectories.end()) {
    subdirectories.erase(dir);
  }
  if (current_kind == KIND_DIRECTORY && it->is_recursive()) {
    if (dir == subdirectories.end()) {
      shared_ptr<DirectoryRecord> subdir(new DirectoryRecord(this, string(entry_name)));
      subdirectories.emplace(entry_name, subdir);
      it->push_directory(subdir);
    } else {
      it->push_directory(dir->second);
    }
  }
}

bool DirectoryRecord::all_populated() const
{
  if (!populated) return false;

  for (auto &pair : subdirectories) {
    if (!pair.second->all_populated()) {
      return false;
    }
  }

  return true;
}

size_t DirectoryRecord::count_entries() const
{
  // Start with 1 to count the readdir() on this directory.
  size_t count = 1;
  for (auto &pair : entries) {
    if ((pair.second.st_mode & S_IFDIR) != S_IFDIR) {
      count++;
    }
  }
  for (auto &pair : subdirectories) {
    count += pair.second->count_entries();
  }
  return count;
}

DirectoryRecord::DirectoryRecord(DirectoryRecord *parent, string &&name) :
  parent{parent},
  name(move(name)),
  populated{false}
{
  //
}

void DirectoryRecord::entry_deleted(BoundPollingIterator *it, const string &entry_path, EntryKind kind)
{
  if (!populated) return;

  it->get_buffer().deleted(string(entry_path), kind);
}

void DirectoryRecord::entry_created(BoundPollingIterator *it, const string &entry_path, EntryKind kind)
{
  if (!populated) return;

  it->get_buffer().created(string(entry_path), kind);
}

void DirectoryRecord::entry_modified(BoundPollingIterator *it, const string &entry_path, EntryKind kind)
{
  if (!populated) return;

  it->get_buffer().modified(string(entry_path), kind);
}
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** 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.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "kitinformation.h"

#include "devicesupport/desktopdevice.h"
#include "devicesupport/devicemanager.h"
#include "projectexplorerconstants.h"
#include "kit.h"
#include "kitinformationconfigwidget.h"
#include "toolchain.h"
#include "toolchainmanager.h"

#include <extensionsystem/pluginmanager.h>
#include <projectexplorer/abi.h>
#include <utils/qtcassert.h>

#include <QFileInfo>

namespace ProjectExplorer {

// --------------------------------------------------------------------------
// SysRootInformation:
// --------------------------------------------------------------------------

static const char SYSROOT_INFORMATION[] = "PE.Profile.SysRoot";

SysRootKitInformation::SysRootKitInformation()
{
    setObjectName(QLatin1String("SysRootInformation"));
}

Core::Id SysRootKitInformation::dataId() const
{
    static const Core::Id id(SYSROOT_INFORMATION);
    return id;
}

unsigned int SysRootKitInformation::priority() const
{
    return 31000;
}

QVariant SysRootKitInformation::defaultValue(Kit *k) const
{
    Q_UNUSED(k)
    return QString();
}

QList<Task> SysRootKitInformation::validate(const Kit *k) const
{
    QList<Task> result;
    const Utils::FileName dir = SysRootKitInformation::sysRoot(k);
    if (!dir.toFileInfo().isDir() && SysRootKitInformation::hasSysRoot(k)) {
        result << Task(Task::Error, tr("Sys Root \"%1\" is not a directory.").arg(dir.toUserOutput()),
                       Utils::FileName(), -1, Core::Id(Constants::TASK_CATEGORY_BUILDSYSTEM));
    }
    return result;
}

KitConfigWidget *SysRootKitInformation::createConfigWidget(Kit *k) const
{
    return new Internal::SysRootInformationConfigWidget(k);
}

KitInformation::ItemList SysRootKitInformation::toUserOutput(const Kit *k) const
{
    return ItemList() << qMakePair(tr("Sys Root"), sysRoot(k).toUserOutput());
}

bool SysRootKitInformation::hasSysRoot(const Kit *k)
{
    if (k)
        return !k->value(Core::Id(SYSROOT_INFORMATION)).toString().isEmpty();
    return false;
}

Utils::FileName SysRootKitInformation::sysRoot(const Kit *k)
{
    if (!k)
        return Utils::FileName();
    return Utils::FileName::fromString(k->value(Core::Id(SYSROOT_INFORMATION)).toString());
}

void SysRootKitInformation::setSysRoot(Kit *k, const Utils::FileName &v)
{
    k->setValue(Core::Id(SYSROOT_INFORMATION), v.toString());
}

// --------------------------------------------------------------------------
// ToolChainInformation:
// --------------------------------------------------------------------------

static const char TOOLCHAIN_INFORMATION[] = "PE.Profile.ToolChain";

ToolChainKitInformation::ToolChainKitInformation()
{
    setObjectName(QLatin1String("ToolChainInformation"));
    connect(KitManager::instance(), SIGNAL(kitsLoaded()),
            this, SLOT(kitsWereLoaded()));
}

Core::Id ToolChainKitInformation::dataId() const
{
    static const Core::Id id(TOOLCHAIN_INFORMATION);
    return id;
}

unsigned int ToolChainKitInformation::priority() const
{
    return 30000;
}

QVariant ToolChainKitInformation::defaultValue(Kit *k) const
{
    Q_UNUSED(k);
    QList<ToolChain *> tcList = ToolChainManager::instance()->toolChains();
    if (tcList.isEmpty())
        return QString();

    ProjectExplorer::Abi abi = ProjectExplorer::Abi::hostAbi();

    foreach (ToolChain *tc, tcList) {
        if (tc->targetAbi() == abi)
            return tc->id();
    }

    return tcList.at(0)->id();
}

QList<Task> ToolChainKitInformation::validate(const Kit *k) const
{
    QList<Task> result;

    const ToolChain* toolchain = toolChain(k);
    if (!toolchain) {
        result << Task(Task::Error, ToolChainKitInformation::msgNoToolChainInTarget(),
                       Utils::FileName(), -1, Core::Id(Constants::TASK_CATEGORY_BUILDSYSTEM));
    } else {
        result << toolchain->validateKit(k);
    }
    return result;
}

void ToolChainKitInformation::fix(Kit *k)
{
    QTC_ASSERT(ToolChainManager::instance()->isLoaded(), return);
    if (toolChain(k))
        return;

    qWarning("Tool chain is no longer known, removing from kit \"%s\".",
             qPrintable(k->displayName()));
    setToolChain(k, 0); // make sure to clear out no longer known tool chains
}

void ToolChainKitInformation::setup(Kit *k)
{
    QTC_ASSERT(ToolChainManager::instance()->isLoaded(), return);
    const QString id = k->value(Core::Id(TOOLCHAIN_INFORMATION)).toString();
    if (id.isEmpty())
        return;

    ToolChain *tc = ToolChainManager::instance()->findToolChain(id);
    if (tc)
        return;

    // ID is not found: Might be an ABI string...
    foreach (ToolChain *current, ToolChainManager::instance()->toolChains()) {
        if (current->targetAbi().toString() == id)
            return setToolChain(k, current);
    }
}

KitConfigWidget *ToolChainKitInformation::createConfigWidget(Kit *k) const
{
    return new Internal::ToolChainInformationConfigWidget(k);
}

QString ToolChainKitInformation::displayNamePostfix(const Kit *k) const
{
    ToolChain *tc = toolChain(k);
    return tc ? tc->displayName() : QString();
}

KitInformation::ItemList ToolChainKitInformation::toUserOutput(const Kit *k) const
{
    ToolChain *tc = toolChain(k);
    return ItemList() << qMakePair(tr("Compiler"), tc ? tc->displayName() : tr("None"));
}

void ToolChainKitInformation::addToEnvironment(const Kit *k, Utils::Environment &env) const
{
    ToolChain *tc = toolChain(k);
    if (tc)
        tc->addToEnvironment(env);
}

IOutputParser *ToolChainKitInformation::createOutputParser(const Kit *k) const
{
    ToolChain *tc = toolChain(k);
    if (tc)
        return tc->outputParser();
    return 0;
}

ToolChain *ToolChainKitInformation::toolChain(const Kit *k)
{
    QTC_ASSERT(ToolChainManager::instance()->isLoaded(), return 0);
    if (!k)
        return 0;
    return ToolChainManager::instance()
            ->findToolChain(k->value(Core::Id(TOOLCHAIN_INFORMATION)).toString());
}

void ToolChainKitInformation::setToolChain(Kit *k, ToolChain *tc)
{
    k->setValue(Core::Id(TOOLCHAIN_INFORMATION), tc ? tc->id() : QString());
}

QString ToolChainKitInformation::msgNoToolChainInTarget()
{
    return tr("No compiler set in kit.");
}

void ToolChainKitInformation::kitsWereLoaded()
{
    foreach (Kit *k, KitManager::instance()->kits())
        fix(k);

    connect(ToolChainManager::instance(), SIGNAL(toolChainRemoved(ProjectExplorer::ToolChain*)),
            this, SLOT(toolChainRemoved(ProjectExplorer::ToolChain*)));
    connect(ToolChainManager::instance(), SIGNAL(toolChainUpdated(ProjectExplorer::ToolChain*)),
            this, SLOT(toolChainUpdated(ProjectExplorer::ToolChain*)));
}

void ToolChainKitInformation::toolChainUpdated(ProjectExplorer::ToolChain *tc)
{
    ToolChainMatcher m(tc);
    foreach (Kit *k, KitManager::instance()->kits(&m))
        notifyAboutUpdate(k);
}

void ToolChainKitInformation::toolChainRemoved(ProjectExplorer::ToolChain *tc)
{
    Q_UNUSED(tc);
    foreach (Kit *k, KitManager::instance()->kits())
        fix(k);
}

// --------------------------------------------------------------------------
// DeviceTypeInformation:
// --------------------------------------------------------------------------

static const char DEVICETYPE_INFORMATION[] = "PE.Profile.DeviceType";

DeviceTypeKitInformation::DeviceTypeKitInformation()
{
    setObjectName(QLatin1String("DeviceTypeInformation"));
}

Core::Id DeviceTypeKitInformation::dataId() const
{
    static const Core::Id id(DEVICETYPE_INFORMATION);
    return id;
}

unsigned int DeviceTypeKitInformation::priority() const
{
    return 33000;
}

QVariant DeviceTypeKitInformation::defaultValue(Kit *k) const
{
    Q_UNUSED(k);
    return QByteArray(Constants::DESKTOP_DEVICE_TYPE);
}

QList<Task> DeviceTypeKitInformation::validate(const Kit *k) const
{
    Q_UNUSED(k);
    return QList<Task>();
}

KitConfigWidget *DeviceTypeKitInformation::createConfigWidget(Kit *k) const
{
    return new Internal::DeviceTypeInformationConfigWidget(k);
}

KitInformation::ItemList DeviceTypeKitInformation::toUserOutput(const Kit *k) const
{
    Core::Id type = deviceTypeId(k);
    QString typeDisplayName = tr("Unknown device type");
    if (type.isValid()) {
        QList<IDeviceFactory *> factories
                = ExtensionSystem::PluginManager::instance()->getObjects<IDeviceFactory>();
        foreach (IDeviceFactory *factory, factories) {
            if (factory->availableCreationIds().contains(type)) {
                typeDisplayName = factory->displayNameForId(type);
                break;
            }
        }
    }
    return ItemList() << qMakePair(tr("Device type"), typeDisplayName);
}

const Core::Id DeviceTypeKitInformation::deviceTypeId(const Kit *k)
{
    return k ? Core::Id::fromSetting(k->value(DEVICETYPE_INFORMATION)) : Core::Id();
}

void DeviceTypeKitInformation::setDeviceTypeId(Kit *k, Core::Id type)
{
    k->setValue(DEVICETYPE_INFORMATION, type.toSetting());
}

// --------------------------------------------------------------------------
// DeviceInformation:
// --------------------------------------------------------------------------

static const char DEVICE_INFORMATION[] = "PE.Profile.Device";

DeviceKitInformation::DeviceKitInformation()
{
    setObjectName(QLatin1String("DeviceInformation"));
    connect(KitManager::instance(), SIGNAL(kitsLoaded()),
            this, SLOT(kitsWereLoaded()));
}

Core::Id DeviceKitInformation::dataId() const
{
    static const Core::Id id(DEVICE_INFORMATION);
    return id;
}

unsigned int DeviceKitInformation::priority() const
{
    return 32000;
}

QVariant DeviceKitInformation::defaultValue(Kit *k) const
{
    Core::Id type = DeviceTypeKitInformation::deviceTypeId(k);
    IDevice::ConstPtr dev = DeviceManager::instance()->defaultDevice(type);
    return dev.isNull() ? QString() : dev->id().toString();
}

QList<Task> DeviceKitInformation::validate(const Kit *k) const
{
    IDevice::ConstPtr dev = DeviceKitInformation::device(k);
    QList<Task> result;
    if (!dev.isNull() && dev->type() != DeviceTypeKitInformation::deviceTypeId(k))
        result.append(Task(Task::Error, tr("Device does not match device type."),
                           Utils::FileName(), -1, Core::Id(Constants::TASK_CATEGORY_BUILDSYSTEM)));
    if (dev.isNull())
        result.append(Task(Task::Warning, tr("No device set."),
                           Utils::FileName(), -1, Core::Id(Constants::TASK_CATEGORY_BUILDSYSTEM)));
    return result;
}

void DeviceKitInformation::fix(Kit *k)
{
    IDevice::ConstPtr dev = DeviceKitInformation::device(k);
    if (!dev.isNull() && dev->type() == DeviceTypeKitInformation::deviceTypeId(k))
        return;

    qWarning("Device is no longer known, removing from kit \"%s\".", qPrintable(k->displayName()));
    setDeviceId(k, Core::Id());
}

void DeviceKitInformation::setup(Kit *k)
{
    QTC_ASSERT(DeviceManager::instance()->isLoaded(), return);
    IDevice::ConstPtr dev = DeviceKitInformation::device(k);
    if (!dev.isNull() && dev->type() == DeviceTypeKitInformation::deviceTypeId(k))
        return;

    setDeviceId(k, Core::Id::fromSetting(defaultValue(k)));
}

KitConfigWidget *DeviceKitInformation::createConfigWidget(Kit *k) const
{
    return new Internal::DeviceInformationConfigWidget(k);
}

QString DeviceKitInformation::displayNamePostfix(const Kit *k) const
{
    IDevice::ConstPtr dev = device(k);
    return dev.isNull() ? QString() : dev->displayName();
}

KitInformation::ItemList DeviceKitInformation::toUserOutput(const Kit *k) const
{
    IDevice::ConstPtr dev = device(k);
    return ItemList() << qMakePair(tr("Device"), dev.isNull() ? tr("Unconfigured") : dev->displayName());
}

IDevice::ConstPtr DeviceKitInformation::device(const Kit *k)
{
    QTC_ASSERT(DeviceManager::instance()->isLoaded(), return IDevice::ConstPtr());
    return DeviceManager::instance()->find(deviceId(k));
}

Core::Id DeviceKitInformation::deviceId(const Kit *k)
{
    return k ? Core::Id::fromSetting(k->value(DEVICE_INFORMATION)) : Core::Id();
}

void DeviceKitInformation::setDevice(Kit *k, IDevice::ConstPtr dev)
{
    setDeviceId(k, dev ? dev->id() : Core::Id());
}

void DeviceKitInformation::setDeviceId(Kit *k, const Core::Id id)
{
    k->setValue(DEVICE_INFORMATION, id.toSetting());
}

void DeviceKitInformation::kitsWereLoaded()
{
    foreach (Kit *k, KitManager::instance()->kits())
        fix(k);

    connect(DeviceManager::instance(), SIGNAL(deviceAdded(Core::Id)),
            this, SLOT(deviceAdded(Core::Id)));
    connect(DeviceManager::instance(), SIGNAL(deviceRemoved(Core::Id)),
            this, SLOT(deviceRemoved(Core::Id)));
    connect(DeviceManager::instance(), SIGNAL(deviceUpdated(Core::Id)),
            this, SLOT(deviceUpdated(Core::Id)));

    connect(KitManager::instance(), SIGNAL(kitUpdated(ProjectExplorer::Kit*)),
            this, SLOT(kitUpdated(ProjectExplorer::Kit*)));
    connect(KitManager::instance(), SIGNAL(unmanagedKitUpdated(ProjectExplorer::Kit*)),
            this, SLOT(kitUpdated(ProjectExplorer::Kit*)));
}

void DeviceKitInformation::deviceUpdated(const Core::Id &id)
{
    foreach (Kit *k, KitManager::instance()->kits()) {
        if (deviceId(k) == id)
            notifyAboutUpdate(k);
    }
}

void DeviceKitInformation::kitUpdated(Kit *k)
{
    setup(k); // Set default device if necessary
}

void DeviceKitInformation::deviceAdded(const Core::Id &id)
{
    Q_UNUSED(id);
    DeviceMatcher m;
    foreach (Kit *k, KitManager::instance()->kits(&m)) {
        setup(k); // Set default device if necessary
    }
}

void DeviceKitInformation::deviceRemoved(const Core::Id &id)
{
    DeviceMatcher m(id);
    foreach (Kit *k, KitManager::instance()->kits(&m))
        setup(k); // Set default device if necessary
}

} // namespace ProjectExplorer
<commit_msg>Toolchain: Better warning when running into kits without tool chains<commit_after>/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** 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.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "kitinformation.h"

#include "devicesupport/desktopdevice.h"
#include "devicesupport/devicemanager.h"
#include "projectexplorerconstants.h"
#include "kit.h"
#include "kitinformationconfigwidget.h"
#include "toolchain.h"
#include "toolchainmanager.h"

#include <extensionsystem/pluginmanager.h>
#include <projectexplorer/abi.h>
#include <utils/qtcassert.h>

#include <QFileInfo>

namespace ProjectExplorer {

// --------------------------------------------------------------------------
// SysRootInformation:
// --------------------------------------------------------------------------

static const char SYSROOT_INFORMATION[] = "PE.Profile.SysRoot";

SysRootKitInformation::SysRootKitInformation()
{
    setObjectName(QLatin1String("SysRootInformation"));
}

Core::Id SysRootKitInformation::dataId() const
{
    static const Core::Id id(SYSROOT_INFORMATION);
    return id;
}

unsigned int SysRootKitInformation::priority() const
{
    return 31000;
}

QVariant SysRootKitInformation::defaultValue(Kit *k) const
{
    Q_UNUSED(k)
    return QString();
}

QList<Task> SysRootKitInformation::validate(const Kit *k) const
{
    QList<Task> result;
    const Utils::FileName dir = SysRootKitInformation::sysRoot(k);
    if (!dir.toFileInfo().isDir() && SysRootKitInformation::hasSysRoot(k)) {
        result << Task(Task::Error, tr("Sys Root \"%1\" is not a directory.").arg(dir.toUserOutput()),
                       Utils::FileName(), -1, Core::Id(Constants::TASK_CATEGORY_BUILDSYSTEM));
    }
    return result;
}

KitConfigWidget *SysRootKitInformation::createConfigWidget(Kit *k) const
{
    return new Internal::SysRootInformationConfigWidget(k);
}

KitInformation::ItemList SysRootKitInformation::toUserOutput(const Kit *k) const
{
    return ItemList() << qMakePair(tr("Sys Root"), sysRoot(k).toUserOutput());
}

bool SysRootKitInformation::hasSysRoot(const Kit *k)
{
    if (k)
        return !k->value(Core::Id(SYSROOT_INFORMATION)).toString().isEmpty();
    return false;
}

Utils::FileName SysRootKitInformation::sysRoot(const Kit *k)
{
    if (!k)
        return Utils::FileName();
    return Utils::FileName::fromString(k->value(Core::Id(SYSROOT_INFORMATION)).toString());
}

void SysRootKitInformation::setSysRoot(Kit *k, const Utils::FileName &v)
{
    k->setValue(Core::Id(SYSROOT_INFORMATION), v.toString());
}

// --------------------------------------------------------------------------
// ToolChainInformation:
// --------------------------------------------------------------------------

static const char TOOLCHAIN_INFORMATION[] = "PE.Profile.ToolChain";

ToolChainKitInformation::ToolChainKitInformation()
{
    setObjectName(QLatin1String("ToolChainInformation"));
    connect(KitManager::instance(), SIGNAL(kitsLoaded()),
            this, SLOT(kitsWereLoaded()));
}

Core::Id ToolChainKitInformation::dataId() const
{
    static const Core::Id id(TOOLCHAIN_INFORMATION);
    return id;
}

unsigned int ToolChainKitInformation::priority() const
{
    return 30000;
}

QVariant ToolChainKitInformation::defaultValue(Kit *k) const
{
    Q_UNUSED(k);
    QList<ToolChain *> tcList = ToolChainManager::instance()->toolChains();
    if (tcList.isEmpty())
        return QString();

    ProjectExplorer::Abi abi = ProjectExplorer::Abi::hostAbi();

    foreach (ToolChain *tc, tcList) {
        if (tc->targetAbi() == abi)
            return tc->id();
    }

    return tcList.at(0)->id();
}

QList<Task> ToolChainKitInformation::validate(const Kit *k) const
{
    QList<Task> result;

    const ToolChain* toolchain = toolChain(k);
    if (!toolchain) {
        result << Task(Task::Error, ToolChainKitInformation::msgNoToolChainInTarget(),
                       Utils::FileName(), -1, Core::Id(Constants::TASK_CATEGORY_BUILDSYSTEM));
    } else {
        result << toolchain->validateKit(k);
    }
    return result;
}

void ToolChainKitInformation::fix(Kit *k)
{
    QTC_ASSERT(ToolChainManager::instance()->isLoaded(), return);
    if (toolChain(k))
        return;

    qWarning("No tool chain set from kit \"%s\".",
             qPrintable(k->displayName()));
    setToolChain(k, 0); // make sure to clear out no longer known tool chains
}

void ToolChainKitInformation::setup(Kit *k)
{
    QTC_ASSERT(ToolChainManager::instance()->isLoaded(), return);
    const QString id = k->value(Core::Id(TOOLCHAIN_INFORMATION)).toString();
    if (id.isEmpty())
        return;

    ToolChain *tc = ToolChainManager::instance()->findToolChain(id);
    if (tc)
        return;

    // ID is not found: Might be an ABI string...
    foreach (ToolChain *current, ToolChainManager::instance()->toolChains()) {
        if (current->targetAbi().toString() == id)
            return setToolChain(k, current);
    }
}

KitConfigWidget *ToolChainKitInformation::createConfigWidget(Kit *k) const
{
    return new Internal::ToolChainInformationConfigWidget(k);
}

QString ToolChainKitInformation::displayNamePostfix(const Kit *k) const
{
    ToolChain *tc = toolChain(k);
    return tc ? tc->displayName() : QString();
}

KitInformation::ItemList ToolChainKitInformation::toUserOutput(const Kit *k) const
{
    ToolChain *tc = toolChain(k);
    return ItemList() << qMakePair(tr("Compiler"), tc ? tc->displayName() : tr("None"));
}

void ToolChainKitInformation::addToEnvironment(const Kit *k, Utils::Environment &env) const
{
    ToolChain *tc = toolChain(k);
    if (tc)
        tc->addToEnvironment(env);
}

IOutputParser *ToolChainKitInformation::createOutputParser(const Kit *k) const
{
    ToolChain *tc = toolChain(k);
    if (tc)
        return tc->outputParser();
    return 0;
}

ToolChain *ToolChainKitInformation::toolChain(const Kit *k)
{
    QTC_ASSERT(ToolChainManager::instance()->isLoaded(), return 0);
    if (!k)
        return 0;
    return ToolChainManager::instance()
            ->findToolChain(k->value(Core::Id(TOOLCHAIN_INFORMATION)).toString());
}

void ToolChainKitInformation::setToolChain(Kit *k, ToolChain *tc)
{
    k->setValue(Core::Id(TOOLCHAIN_INFORMATION), tc ? tc->id() : QString());
}

QString ToolChainKitInformation::msgNoToolChainInTarget()
{
    return tr("No compiler set in kit.");
}

void ToolChainKitInformation::kitsWereLoaded()
{
    foreach (Kit *k, KitManager::instance()->kits())
        fix(k);

    connect(ToolChainManager::instance(), SIGNAL(toolChainRemoved(ProjectExplorer::ToolChain*)),
            this, SLOT(toolChainRemoved(ProjectExplorer::ToolChain*)));
    connect(ToolChainManager::instance(), SIGNAL(toolChainUpdated(ProjectExplorer::ToolChain*)),
            this, SLOT(toolChainUpdated(ProjectExplorer::ToolChain*)));
}

void ToolChainKitInformation::toolChainUpdated(ProjectExplorer::ToolChain *tc)
{
    ToolChainMatcher m(tc);
    foreach (Kit *k, KitManager::instance()->kits(&m))
        notifyAboutUpdate(k);
}

void ToolChainKitInformation::toolChainRemoved(ProjectExplorer::ToolChain *tc)
{
    Q_UNUSED(tc);
    foreach (Kit *k, KitManager::instance()->kits())
        fix(k);
}

// --------------------------------------------------------------------------
// DeviceTypeInformation:
// --------------------------------------------------------------------------

static const char DEVICETYPE_INFORMATION[] = "PE.Profile.DeviceType";

DeviceTypeKitInformation::DeviceTypeKitInformation()
{
    setObjectName(QLatin1String("DeviceTypeInformation"));
}

Core::Id DeviceTypeKitInformation::dataId() const
{
    static const Core::Id id(DEVICETYPE_INFORMATION);
    return id;
}

unsigned int DeviceTypeKitInformation::priority() const
{
    return 33000;
}

QVariant DeviceTypeKitInformation::defaultValue(Kit *k) const
{
    Q_UNUSED(k);
    return QByteArray(Constants::DESKTOP_DEVICE_TYPE);
}

QList<Task> DeviceTypeKitInformation::validate(const Kit *k) const
{
    Q_UNUSED(k);
    return QList<Task>();
}

KitConfigWidget *DeviceTypeKitInformation::createConfigWidget(Kit *k) const
{
    return new Internal::DeviceTypeInformationConfigWidget(k);
}

KitInformation::ItemList DeviceTypeKitInformation::toUserOutput(const Kit *k) const
{
    Core::Id type = deviceTypeId(k);
    QString typeDisplayName = tr("Unknown device type");
    if (type.isValid()) {
        QList<IDeviceFactory *> factories
                = ExtensionSystem::PluginManager::instance()->getObjects<IDeviceFactory>();
        foreach (IDeviceFactory *factory, factories) {
            if (factory->availableCreationIds().contains(type)) {
                typeDisplayName = factory->displayNameForId(type);
                break;
            }
        }
    }
    return ItemList() << qMakePair(tr("Device type"), typeDisplayName);
}

const Core::Id DeviceTypeKitInformation::deviceTypeId(const Kit *k)
{
    return k ? Core::Id::fromSetting(k->value(DEVICETYPE_INFORMATION)) : Core::Id();
}

void DeviceTypeKitInformation::setDeviceTypeId(Kit *k, Core::Id type)
{
    k->setValue(DEVICETYPE_INFORMATION, type.toSetting());
}

// --------------------------------------------------------------------------
// DeviceInformation:
// --------------------------------------------------------------------------

static const char DEVICE_INFORMATION[] = "PE.Profile.Device";

DeviceKitInformation::DeviceKitInformation()
{
    setObjectName(QLatin1String("DeviceInformation"));
    connect(KitManager::instance(), SIGNAL(kitsLoaded()),
            this, SLOT(kitsWereLoaded()));
}

Core::Id DeviceKitInformation::dataId() const
{
    static const Core::Id id(DEVICE_INFORMATION);
    return id;
}

unsigned int DeviceKitInformation::priority() const
{
    return 32000;
}

QVariant DeviceKitInformation::defaultValue(Kit *k) const
{
    Core::Id type = DeviceTypeKitInformation::deviceTypeId(k);
    IDevice::ConstPtr dev = DeviceManager::instance()->defaultDevice(type);
    return dev.isNull() ? QString() : dev->id().toString();
}

QList<Task> DeviceKitInformation::validate(const Kit *k) const
{
    IDevice::ConstPtr dev = DeviceKitInformation::device(k);
    QList<Task> result;
    if (!dev.isNull() && dev->type() != DeviceTypeKitInformation::deviceTypeId(k))
        result.append(Task(Task::Error, tr("Device does not match device type."),
                           Utils::FileName(), -1, Core::Id(Constants::TASK_CATEGORY_BUILDSYSTEM)));
    if (dev.isNull())
        result.append(Task(Task::Warning, tr("No device set."),
                           Utils::FileName(), -1, Core::Id(Constants::TASK_CATEGORY_BUILDSYSTEM)));
    return result;
}

void DeviceKitInformation::fix(Kit *k)
{
    IDevice::ConstPtr dev = DeviceKitInformation::device(k);
    if (!dev.isNull() && dev->type() == DeviceTypeKitInformation::deviceTypeId(k))
        return;

    qWarning("Device is no longer known, removing from kit \"%s\".", qPrintable(k->displayName()));
    setDeviceId(k, Core::Id());
}

void DeviceKitInformation::setup(Kit *k)
{
    QTC_ASSERT(DeviceManager::instance()->isLoaded(), return);
    IDevice::ConstPtr dev = DeviceKitInformation::device(k);
    if (!dev.isNull() && dev->type() == DeviceTypeKitInformation::deviceTypeId(k))
        return;

    setDeviceId(k, Core::Id::fromSetting(defaultValue(k)));
}

KitConfigWidget *DeviceKitInformation::createConfigWidget(Kit *k) const
{
    return new Internal::DeviceInformationConfigWidget(k);
}

QString DeviceKitInformation::displayNamePostfix(const Kit *k) const
{
    IDevice::ConstPtr dev = device(k);
    return dev.isNull() ? QString() : dev->displayName();
}

KitInformation::ItemList DeviceKitInformation::toUserOutput(const Kit *k) const
{
    IDevice::ConstPtr dev = device(k);
    return ItemList() << qMakePair(tr("Device"), dev.isNull() ? tr("Unconfigured") : dev->displayName());
}

IDevice::ConstPtr DeviceKitInformation::device(const Kit *k)
{
    QTC_ASSERT(DeviceManager::instance()->isLoaded(), return IDevice::ConstPtr());
    return DeviceManager::instance()->find(deviceId(k));
}

Core::Id DeviceKitInformation::deviceId(const Kit *k)
{
    return k ? Core::Id::fromSetting(k->value(DEVICE_INFORMATION)) : Core::Id();
}

void DeviceKitInformation::setDevice(Kit *k, IDevice::ConstPtr dev)
{
    setDeviceId(k, dev ? dev->id() : Core::Id());
}

void DeviceKitInformation::setDeviceId(Kit *k, const Core::Id id)
{
    k->setValue(DEVICE_INFORMATION, id.toSetting());
}

void DeviceKitInformation::kitsWereLoaded()
{
    foreach (Kit *k, KitManager::instance()->kits())
        fix(k);

    connect(DeviceManager::instance(), SIGNAL(deviceAdded(Core::Id)),
            this, SLOT(deviceAdded(Core::Id)));
    connect(DeviceManager::instance(), SIGNAL(deviceRemoved(Core::Id)),
            this, SLOT(deviceRemoved(Core::Id)));
    connect(DeviceManager::instance(), SIGNAL(deviceUpdated(Core::Id)),
            this, SLOT(deviceUpdated(Core::Id)));

    connect(KitManager::instance(), SIGNAL(kitUpdated(ProjectExplorer::Kit*)),
            this, SLOT(kitUpdated(ProjectExplorer::Kit*)));
    connect(KitManager::instance(), SIGNAL(unmanagedKitUpdated(ProjectExplorer::Kit*)),
            this, SLOT(kitUpdated(ProjectExplorer::Kit*)));
}

void DeviceKitInformation::deviceUpdated(const Core::Id &id)
{
    foreach (Kit *k, KitManager::instance()->kits()) {
        if (deviceId(k) == id)
            notifyAboutUpdate(k);
    }
}

void DeviceKitInformation::kitUpdated(Kit *k)
{
    setup(k); // Set default device if necessary
}

void DeviceKitInformation::deviceAdded(const Core::Id &id)
{
    Q_UNUSED(id);
    DeviceMatcher m;
    foreach (Kit *k, KitManager::instance()->kits(&m)) {
        setup(k); // Set default device if necessary
    }
}

void DeviceKitInformation::deviceRemoved(const Core::Id &id)
{
    DeviceMatcher m(id);
    foreach (Kit *k, KitManager::instance()->kits(&m))
        setup(k); // Set default device if necessary
}

} // namespace ProjectExplorer
<|endoftext|>


<commit_before>/*******************************************************************************

Licensed to the OpenCOR team under one or more contributor license agreements.
See the NOTICE.txt file distributed with this work for additional information
regarding copyright ownership. The OpenCOR team licenses this file to you under
the Apache License, Version 2.0 (the "License"); you may not use this file
except in compliance with the License. You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied. See the License for the
specific language governing permissions and limitations under the License.

*******************************************************************************/

//==============================================================================
// Editor widget
//==============================================================================

#include "editorfindreplacewidget.h"
#include "editorwidget.h"
#include "guiutils.h"
#include "qscintillawidget.h"

//==============================================================================

#include "ui_editorwidget.h"

//==============================================================================

#include <Qt>

//==============================================================================

#include <QFrame>
#include <QKeyEvent>
#include <QLabel>
#include <QLayout>
#include <QVBoxLayout>

//==============================================================================

namespace OpenCOR {
namespace Editor {

//==============================================================================

EditorWidget::EditorWidget(const QString &pContents, const bool &pReadOnly,
                           QsciLexer *pLexer, QWidget *pParent) :
    Core::Widget(pParent),
    mGui(new Ui::EditorWidget)
{
    // Set up the GUI

    mGui->setupUi(this);

    // Create our editor and find/replace widget

    mEditor = new QScintillaSupport::QScintillaWidget(pContents, pReadOnly,
                                                      pLexer, this);
    mSeparator = Core::newLineWidget(this);
    mFindReplace = new EditorFindReplaceWidget(this);

    // Forward some signals that are emitted by our editor

    connect(mEditor, SIGNAL(SCN_ZOOM()),
            this, SLOT(zoomLevelChanged()));

    connect(mEditor, SIGNAL(cursorPositionChanged(int, int)),
            this, SIGNAL(cursorPositionChanged(const int &, const int &)));

    connect(mEditor, SIGNAL(textChanged()),
            this, SIGNAL(textChanged()));

    connect(mEditor, SIGNAL(copyAvailable(bool)),
            this, SIGNAL(copyAvailable(const bool &)));

    connect(mEditor, SIGNAL(canUndo(const bool &)),
            this, SIGNAL(canUndo(const bool &)));
    connect(mEditor, SIGNAL(canRedo(const bool &)),
            this, SIGNAL(canRedo(const bool &)));

    connect(mEditor, SIGNAL(canSelectAll(const bool &)),
            this, SIGNAL(canSelectAll(const bool &)));

    // Keep track of whenever a key is being pressed in our editor our
    // find/replace widget

    connect(mEditor, SIGNAL(keyPressed(QKeyEvent *, bool &)),
            this, SLOT(keyPressed(QKeyEvent *, bool &)));
    connect(mFindReplace, SIGNAL(keyPressed(QKeyEvent *, bool &)),
            this, SLOT(keyPressed(QKeyEvent *, bool &)));

    // Add our editor and find/replace widgets to our layout

    mGui->layout->addWidget(mEditor);
    mGui->layout->addWidget(mSeparator);
    mGui->layout->addWidget(mFindReplace);

    // Make our editor our focus proxy

    setFocusProxy(mEditor);

    // Retranslate ourselves, so our find/replace widget is properly set

    retranslateUi();

    // Initially hide our find/replace widget

    hideFindReplace();
}

//==============================================================================

void EditorWidget::retranslateUi()
{
    // Retranslate our find/replace widget

    mFindReplace->retranslateUi();
}

//==============================================================================

QMenu * EditorWidget::contextMenu() const
{
    // Return the context menu of our editor

    return mEditor->contextMenu();
}

//==============================================================================

void EditorWidget::setContextMenu(const QList<QAction *> &pContextMenuActions)
{
    // Set the context menu of our editor

    mEditor->setContextMenu(pContextMenuActions);
}

//==============================================================================

int EditorWidget::currentPosition() const
{
    // Return the current position of our editor

    return mEditor->currentPosition();
}

//==============================================================================

QString EditorWidget::contents() const
{
    // Return the contents of our editor

    return mEditor->contents();
}

//==============================================================================

void EditorWidget::setContents(const QString &pContents)
{
    // Set the contents of our editor

    mEditor->setContents(pContents);
}

//==============================================================================

int EditorWidget::contentsSize() const
{
    // Return the size of the contents of our editor

    return mEditor->contentsSize();
}

//==============================================================================

bool EditorWidget::isReadOnly() const
{
    // Return whether our editor is in read-only mode

    return mEditor->isReadOnly();
}

//==============================================================================

void EditorWidget::setReadOnly(const bool &pReadOnly)
{
    // Set the read-only mode of our editor

    mEditor->setReadOnly(pReadOnly);
}

//==============================================================================

bool EditorWidget::hasSelectedText() const
{
    // Return whether our editor has some text selected

    return mEditor->hasSelectedText();
}

//==============================================================================

QString EditorWidget::selectedText() const
{
    // Return whether the selected text, if any, in our editor

    return mEditor->selectedText();
}

//==============================================================================

QString EditorWidget::textInRange(const int &pStartRange,
                                  const int &pEndRange) const
{
    // Retrieve and return the text in the given range in our editor, making
    // sure that the given range makes sense

    return mEditor->textInRange(pStartRange, pEndRange);
}

//==============================================================================

int EditorWidget::findTextInRange(const int &pStartRange, const int &pEndRange,
                                  const QString &pText,
                                  const bool &pCaseSensitive) const
{
    // Find and return the position, if any, of the given text within the given
    // range in our editor

    return mEditor->findTextInRange(pStartRange, pEndRange, pText, pCaseSensitive);
}

//==============================================================================

bool EditorWidget::isUndoAvailable() const
{
    // Return whether we can undo a change in our editor

    return mEditor->isUndoAvailable();
}

//==============================================================================

bool EditorWidget::isRedoAvailable() const
{
    // Return whether we can redo a change in our editor

    return mEditor->isRedoAvailable();
}

//==============================================================================

bool EditorWidget::isSelectAllAvailable() const
{
    // Return whether we can select all the text in our editor

    return mEditor->isSelectAllAvailable();
}

//==============================================================================

void EditorWidget::cut()
{
    // Cut the selected text, if any, in our editor

    mEditor->cut();
}

//==============================================================================

void EditorWidget::copy()
{
    // Copy the selected text, if any, in our editor

    mEditor->copy();
}

//==============================================================================

void EditorWidget::paste()
{
    // Paste the text, if any available, in our editor

    mEditor->paste();
}

//==============================================================================

void EditorWidget::del()
{
    // Delete the selected text, if any, in our editor

    mEditor->del();
}

//==============================================================================

void EditorWidget::undo()
{
    // Undo the last change, if any, in our editor

    mEditor->undo();
}

//==============================================================================

void EditorWidget::redo()
{
    // Redo the last change, if any, in our editor

    mEditor->redo();
}

//==============================================================================

void EditorWidget::selectAll()
{
    // Select all the text, if any, in our editor

    mEditor->selectAll();
}

//==============================================================================

void EditorWidget::resetUndoHistory()
{
    // Reset the undo history of our editor

    mEditor->resetUndoHistory();
}

//==============================================================================

QLabel * EditorWidget::cursorPositionWidget() const
{
    // Return the cursort position widget of our editor

    return mEditor->cursorPositionWidget();
}

//==============================================================================

QLabel * EditorWidget::editingModeWidget() const
{
    // Return the editing mode widget of our editor

    return mEditor->editingModeWidget();
}

//==============================================================================

QString EditorWidget::eolString() const
{
    // Return the end of line used by our editor

    return mEditor->eolString();
}

//==============================================================================

void EditorWidget::setBackgroundColor(const int &pStyle,
                                      const QColor &pBackgroundColor)
{
    // Set the background color for the given style in our editor

    mEditor->setBackgroundColor(pStyle, pBackgroundColor);
}

//==============================================================================

void EditorWidget::setForegroundColor(const int &pStyle,
                                      const QColor &pForegroundColor)
{
    // Set the foreground color for the given style in our editor

    mEditor->setForegroundColor(pStyle, pForegroundColor);
}

//==============================================================================

int EditorWidget::zoomLevel() const
{
    // Return the zoom level of our editor

    return mEditor->zoomLevel();
}

//==============================================================================

void EditorWidget::setZoomLevel(const int &pZoomLevel)
{
    // Set the zoom level of our editor

    return mEditor->zoomTo(pZoomLevel);
}

//==============================================================================

void EditorWidget::showFindReplace()
{
    // Show our find/replace widget

    mSeparator->setVisible(true);
    mFindReplace->setVisible(true);

    // Give the focus to our find/replace widget and hide our editor's caret

    mFindReplace->setFocus();
}

//==============================================================================

void EditorWidget::hideFindReplace()
{
    // Hide our find/replace widget

    mSeparator->setVisible(false);
    mFindReplace->setVisible(false);

    // Give the focus (back) to our editor and show its caret

    mEditor->setFocus();
}

//==============================================================================

void EditorWidget::zoomLevelChanged()
{
    // Let people know that the zoom level has changed

    emit zoomLevelChanged(zoomLevel());
}

//==============================================================================

void EditorWidget::keyPressed(QKeyEvent *pEvent, bool &pHandled)
{
    // Show/hide our find/replace widget, if needed

    if (    (sender() == mEditor)
        && !(pEvent->modifiers() & Qt::ShiftModifier)
        &&  (pEvent->modifiers() & Qt::ControlModifier)
        && !(pEvent->modifiers() & Qt::AltModifier)
        && !(pEvent->modifiers() & Qt::MetaModifier)
        &&  (pEvent->key() == Qt::Key_F)) {
        showFindReplace();

        pHandled = true;
    } else if (   !(pEvent->modifiers() & Qt::ShiftModifier)
               && !(pEvent->modifiers() & Qt::ControlModifier)
               && !(pEvent->modifiers() & Qt::AltModifier)
               && !(pEvent->modifiers() & Qt::MetaModifier)
               &&  (pEvent->key() == Qt::Key_Escape)) {
        hideFindReplace();

        pHandled = true;
    } else {
        pHandled = false;
    }
}

//==============================================================================

}   // namespace Editor
}   // namespace OpenCOR

//==============================================================================
// End of file
//==============================================================================
<commit_msg>Some work towards supporting find/replace in our QScintilla-based widget (#261).<commit_after>/*******************************************************************************

Licensed to the OpenCOR team under one or more contributor license agreements.
See the NOTICE.txt file distributed with this work for additional information
regarding copyright ownership. The OpenCOR team licenses this file to you under
the Apache License, Version 2.0 (the "License"); you may not use this file
except in compliance with the License. You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied. See the License for the
specific language governing permissions and limitations under the License.

*******************************************************************************/

//==============================================================================
// Editor widget
//==============================================================================

#include "editorfindreplacewidget.h"
#include "editorwidget.h"
#include "guiutils.h"
#include "qscintillawidget.h"

//==============================================================================

#include "ui_editorwidget.h"

//==============================================================================

#include <Qt>

//==============================================================================

#include <QFrame>
#include <QKeyEvent>
#include <QLabel>
#include <QLayout>
#include <QVBoxLayout>

//==============================================================================

namespace OpenCOR {
namespace Editor {

//==============================================================================

EditorWidget::EditorWidget(const QString &pContents, const bool &pReadOnly,
                           QsciLexer *pLexer, QWidget *pParent) :
    Core::Widget(pParent),
    mGui(new Ui::EditorWidget)
{
    // Set up the GUI

    mGui->setupUi(this);

    // Create our editor and find/replace widget

    mEditor = new QScintillaSupport::QScintillaWidget(pContents, pReadOnly,
                                                      pLexer, this);
    mSeparator = Core::newLineWidget(this);
    mFindReplace = new EditorFindReplaceWidget(this);

    // Disable the focus policy on our editor so that tabbing only works within
    // our find/replace widget

    mEditor->setFocusPolicy(Qt::NoFocus);

    // Forward some signals that are emitted by our editor

    connect(mEditor, SIGNAL(SCN_ZOOM()),
            this, SLOT(zoomLevelChanged()));

    connect(mEditor, SIGNAL(cursorPositionChanged(int, int)),
            this, SIGNAL(cursorPositionChanged(const int &, const int &)));

    connect(mEditor, SIGNAL(textChanged()),
            this, SIGNAL(textChanged()));

    connect(mEditor, SIGNAL(copyAvailable(bool)),
            this, SIGNAL(copyAvailable(const bool &)));

    connect(mEditor, SIGNAL(canUndo(const bool &)),
            this, SIGNAL(canUndo(const bool &)));
    connect(mEditor, SIGNAL(canRedo(const bool &)),
            this, SIGNAL(canRedo(const bool &)));

    connect(mEditor, SIGNAL(canSelectAll(const bool &)),
            this, SIGNAL(canSelectAll(const bool &)));

    // Keep track of whenever a key is being pressed in our editor our
    // find/replace widget

    connect(mEditor, SIGNAL(keyPressed(QKeyEvent *, bool &)),
            this, SLOT(keyPressed(QKeyEvent *, bool &)));
    connect(mFindReplace, SIGNAL(keyPressed(QKeyEvent *, bool &)),
            this, SLOT(keyPressed(QKeyEvent *, bool &)));

    // Add our editor and find/replace widgets to our layout

    mGui->layout->addWidget(mEditor);
    mGui->layout->addWidget(mSeparator);
    mGui->layout->addWidget(mFindReplace);

    // Make our editor our focus proxy

    setFocusProxy(mEditor);

    // Retranslate ourselves, so our find/replace widget is properly set

    retranslateUi();

    // Initially hide our find/replace widget

    hideFindReplace();
}

//==============================================================================

void EditorWidget::retranslateUi()
{
    // Retranslate our find/replace widget

    mFindReplace->retranslateUi();
}

//==============================================================================

QMenu * EditorWidget::contextMenu() const
{
    // Return the context menu of our editor

    return mEditor->contextMenu();
}

//==============================================================================

void EditorWidget::setContextMenu(const QList<QAction *> &pContextMenuActions)
{
    // Set the context menu of our editor

    mEditor->setContextMenu(pContextMenuActions);
}

//==============================================================================

int EditorWidget::currentPosition() const
{
    // Return the current position of our editor

    return mEditor->currentPosition();
}

//==============================================================================

QString EditorWidget::contents() const
{
    // Return the contents of our editor

    return mEditor->contents();
}

//==============================================================================

void EditorWidget::setContents(const QString &pContents)
{
    // Set the contents of our editor

    mEditor->setContents(pContents);
}

//==============================================================================

int EditorWidget::contentsSize() const
{
    // Return the size of the contents of our editor

    return mEditor->contentsSize();
}

//==============================================================================

bool EditorWidget::isReadOnly() const
{
    // Return whether our editor is in read-only mode

    return mEditor->isReadOnly();
}

//==============================================================================

void EditorWidget::setReadOnly(const bool &pReadOnly)
{
    // Set the read-only mode of our editor

    mEditor->setReadOnly(pReadOnly);
}

//==============================================================================

bool EditorWidget::hasSelectedText() const
{
    // Return whether our editor has some text selected

    return mEditor->hasSelectedText();
}

//==============================================================================

QString EditorWidget::selectedText() const
{
    // Return whether the selected text, if any, in our editor

    return mEditor->selectedText();
}

//==============================================================================

QString EditorWidget::textInRange(const int &pStartRange,
                                  const int &pEndRange) const
{
    // Retrieve and return the text in the given range in our editor, making
    // sure that the given range makes sense

    return mEditor->textInRange(pStartRange, pEndRange);
}

//==============================================================================

int EditorWidget::findTextInRange(const int &pStartRange, const int &pEndRange,
                                  const QString &pText,
                                  const bool &pCaseSensitive) const
{
    // Find and return the position, if any, of the given text within the given
    // range in our editor

    return mEditor->findTextInRange(pStartRange, pEndRange, pText, pCaseSensitive);
}

//==============================================================================

bool EditorWidget::isUndoAvailable() const
{
    // Return whether we can undo a change in our editor

    return mEditor->isUndoAvailable();
}

//==============================================================================

bool EditorWidget::isRedoAvailable() const
{
    // Return whether we can redo a change in our editor

    return mEditor->isRedoAvailable();
}

//==============================================================================

bool EditorWidget::isSelectAllAvailable() const
{
    // Return whether we can select all the text in our editor

    return mEditor->isSelectAllAvailable();
}

//==============================================================================

void EditorWidget::cut()
{
    // Cut the selected text, if any, in our editor

    mEditor->cut();
}

//==============================================================================

void EditorWidget::copy()
{
    // Copy the selected text, if any, in our editor

    mEditor->copy();
}

//==============================================================================

void EditorWidget::paste()
{
    // Paste the text, if any available, in our editor

    mEditor->paste();
}

//==============================================================================

void EditorWidget::del()
{
    // Delete the selected text, if any, in our editor

    mEditor->del();
}

//==============================================================================

void EditorWidget::undo()
{
    // Undo the last change, if any, in our editor

    mEditor->undo();
}

//==============================================================================

void EditorWidget::redo()
{
    // Redo the last change, if any, in our editor

    mEditor->redo();
}

//==============================================================================

void EditorWidget::selectAll()
{
    // Select all the text, if any, in our editor

    mEditor->selectAll();
}

//==============================================================================

void EditorWidget::resetUndoHistory()
{
    // Reset the undo history of our editor

    mEditor->resetUndoHistory();
}

//==============================================================================

QLabel * EditorWidget::cursorPositionWidget() const
{
    // Return the cursort position widget of our editor

    return mEditor->cursorPositionWidget();
}

//==============================================================================

QLabel * EditorWidget::editingModeWidget() const
{
    // Return the editing mode widget of our editor

    return mEditor->editingModeWidget();
}

//==============================================================================

QString EditorWidget::eolString() const
{
    // Return the end of line used by our editor

    return mEditor->eolString();
}

//==============================================================================

void EditorWidget::setBackgroundColor(const int &pStyle,
                                      const QColor &pBackgroundColor)
{
    // Set the background color for the given style in our editor

    mEditor->setBackgroundColor(pStyle, pBackgroundColor);
}

//==============================================================================

void EditorWidget::setForegroundColor(const int &pStyle,
                                      const QColor &pForegroundColor)
{
    // Set the foreground color for the given style in our editor

    mEditor->setForegroundColor(pStyle, pForegroundColor);
}

//==============================================================================

int EditorWidget::zoomLevel() const
{
    // Return the zoom level of our editor

    return mEditor->zoomLevel();
}

//==============================================================================

void EditorWidget::setZoomLevel(const int &pZoomLevel)
{
    // Set the zoom level of our editor

    return mEditor->zoomTo(pZoomLevel);
}

//==============================================================================

void EditorWidget::showFindReplace()
{
    // Show our find/replace widget

    mSeparator->setVisible(true);
    mFindReplace->setVisible(true);

    // Give the focus to our find/replace widget and hide our editor's caret

    mFindReplace->setFocus();
}

//==============================================================================

void EditorWidget::hideFindReplace()
{
    // Hide our find/replace widget

    mSeparator->setVisible(false);
    mFindReplace->setVisible(false);

    // Give the focus (back) to our editor and show its caret

    mEditor->setFocus();
}

//==============================================================================

void EditorWidget::zoomLevelChanged()
{
    // Let people know that the zoom level has changed

    emit zoomLevelChanged(zoomLevel());
}

//==============================================================================

void EditorWidget::keyPressed(QKeyEvent *pEvent, bool &pHandled)
{
    // Show/hide our find/replace widget, if needed

    if (    (sender() == mEditor)
        && !(pEvent->modifiers() & Qt::ShiftModifier)
        &&  (pEvent->modifiers() & Qt::ControlModifier)
        && !(pEvent->modifiers() & Qt::AltModifier)
        && !(pEvent->modifiers() & Qt::MetaModifier)
        &&  (pEvent->key() == Qt::Key_F)) {
        showFindReplace();

        pHandled = true;
    } else if (   !(pEvent->modifiers() & Qt::ShiftModifier)
               && !(pEvent->modifiers() & Qt::ControlModifier)
               && !(pEvent->modifiers() & Qt::AltModifier)
               && !(pEvent->modifiers() & Qt::MetaModifier)
               &&  (pEvent->key() == Qt::Key_Escape)) {
        hideFindReplace();

        pHandled = true;
    } else {
        pHandled = false;
    }
}

//==============================================================================

}   // namespace Editor
}   // namespace OpenCOR

//==============================================================================
// End of file
//==============================================================================
<|endoftext|>