<commit_before>#ifndef CPPUT_TESTHARNESS_HPP
#define CPPUT_TESTHARNESS_HPP

///////////////////////////////////////////////////////////////////////////////
///
/// \brief    A light-weight and easy to use unit testing framework for C++
/// \details  Header-only unit testing framework that makes unit testing easy
///           and quick to set up.
/// \version  0.2.0
/// \date     December 2011
/// \author   Tommy Back
///
///
/// Simply include this header file to get started.
///
/// \code
/// #include <cpput/TestHarness.h>
/// #include <Foo.h>
///
/// TEST(Foo, some_descriptive_name)
/// {
///   // Arrange
///   Foo foo;
///   // Act
///   bool result = foo.isBar();
///   // Assert
///   ASSERT_TRUE(result);
/// }
/// \endcode
///
/// In case you want to keep a single file with tests that compile to an
/// executable you can also add the main function to the end of the file.
/// This is simple to do with the provided macro:
///
/// \code
/// CPPUT_TEST_MAIN;
/// \endcode
///
/// For larger test suits, it's recommended to group the tests per class
/// in separate files and let the compiler combine them into a single
/// executable which has a main.cpp file that only has the main function
/// declared.
///
/// \example
/// [Test_Foo.cpp]
///
/// \code
/// #include <cpput/TestHarness.h>
/// #include <Foo.h>
///
/// TEST(Foo, foo_bar_z)
/// {
///   ...
/// \endcode
///
/// [main.cpp]
///
/// \code
/// #include <cpput/TestHarness.h>
///
/// CPPUT_TEST_MAIN;
/// \endcode
///
///

#include <iostream>
#include <iomanip>
#include <string>
#include <sstream>
#include <ctime>

namespace cpput
{

struct ResultWriter
{
  virtual ~ResultWriter() {}

  virtual void startTest(const std::string& className, const std::string& name) = 0;
  virtual void endTest(bool success) = 0;

  virtual void failure(const std::string& filename, std::size_t line, const std::string& message) = 0;
  virtual int getNumberOfFailures() const = 0;
};

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

class TextResultWriter : public ResultWriter
{
public:
  TextResultWriter()
    : testCount_(0)
    , failures_(0)
  {
  }

  virtual ~TextResultWriter()
  {
    if (failures_ == 0)
    {
      std::cout << "\nAll tests pass.\n";
      return;
    }
    std::cout << "\n" << failures_ << " out of " << testCount_ << " tests failed.\n";
  }

  virtual void startTest(const std::string&, const std::string&)
  {
    testCount_++;
  }

  virtual void endTest(bool success)
  {
    if (success)
      std::cout << '.';
    else
      std::cout << 'F';
  }

  virtual void failure(const std::string& filename, std::size_t line, const std::string& message)
  {
    failures_++;
    std::cout << "Failure: " << filename << ", line " << line << ": " << message << '\n';
  }

  virtual int getNumberOfFailures() const { return failures_; }

private:
  int testCount_;
  int failures_;
};

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

class XmlResultWriter : public ResultWriter
{
public:
  XmlResultWriter()
    : startTime_(0)
  {
    std::cout << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
    std::cout << "<testsuite>\n";
  }

  virtual ~XmlResultWriter()
  {
    std::cout << "</testsuite>\n";
  }

  virtual void startTest(const std::string& className, const std::string& name)
  {
    startTime_ = std::clock();
    std::cout << "  <testcase classname=\""
              << className
              << "\" name=\""
              << name
              << "\" time=\"";
  }

  virtual void endTest(bool success)
  {
    if (success)
    {
      std::cout << static_cast<float>(std::clock()-startTime_)/CLOCKS_PER_SEC << "\"";
      std::cout << "/>\n";
    }
    else
      std::cout << "  </testcase>\n";
  }

  virtual void failure(const std::string& filename, std::size_t line, const std::string& message)
  {
    std::cout << static_cast<float>(std::clock()-startTime_)/CLOCKS_PER_SEC << "\"";
    std::cout << ">\n"
              << "    <failure>"
              << message
              << " in "
              << filename
              << ", line "
              << line
              << "</failure>\n";
    failureCount_++;
  }

  virtual int getNumberOfFailures() const
  {
    return failureCount_;
  }

private:
  std::clock_t startTime_;
  int          failureCount_;
};

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

struct Result
{
  Result(const std::string& testClassName,
         const std::string& testName,
         ResultWriter& out)
    : out_(out)
    , pass_(true)
  {
    out_.startTest(testClassName, testName);
  }

  ~Result()
  {
    out_.endTest(pass_);
  }

  template <typename T, typename U>
  void addFailure(const char* filename,
                  std::size_t line,
                  T expected,
                  U actual)
  {
    pass_ = false;
    std::stringstream ss;
    ss << std::setprecision(20)
       << "failed comparison, expected " << expected
       << " got " << actual << "\n";
    out_.failure(filename, line, ss.str());
  }

  void addFailure(const char* filename,
                  std::size_t line,
                  const char* message)
  {
    pass_ = false;
    out_.failure(filename, line, message);
  }

  ResultWriter& out_;
  bool          pass_;
};

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

class Repository;

class Test
{
  friend class Repository;

public:
  Test(const char* className, const char* name);
  virtual ~Test() {}

  void run(ResultWriter& out)
  {
    Result result(test_unit_class_name_, test_unit_name_, out);
    try
    {
      do_run(result);
    }
    catch (const std::exception& e)
    {
      result.addFailure(__FILE__, __LINE__, std::string("Unexpected exception: ").append(e.what()).c_str());
    }
    catch (...)
    {
      result.addFailure(__FILE__, __LINE__, "Unspecified exception!");
    }
  }

  Test* next() { return test_unit_next_; }

private:
  virtual void do_run(Result& testResult_) = 0;

private:
  std::string test_unit_class_name_;
  std::string test_unit_name_;
  Test*       test_unit_next_;
};

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

class Repository
{
public:
  static Repository& instance()
  {
    static Repository repo;
    return repo;
  }

  void add(Test* tc)
  {
    if (!tests_)
    {
      tests_ = tc;
      return;
    }

    // add as last
    Test* tmp = tests_;
    while (tmp->test_unit_next_)
      tmp = tmp->test_unit_next_;
    tmp->test_unit_next_ = tc;
  }

  Test* getTests() { return tests_; }

private:
  Repository() : tests_(0) {}
  Repository(const Repository& other);
  Repository& operator=(const Repository& rhs) const;

private:
  Test* tests_;
};

inline Test::Test(const char* className, const char* name)
  : test_unit_class_name_(className)
  , test_unit_name_(name)
  , test_unit_next_(0)
{
  Repository::instance().add(this);
}

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

inline int runAllTests(ResultWriter& writer)
{
  Test* c = Repository::instance().getTests();
  while (c)
  {
    c->run(writer);
    c = c->next();
  }
  return writer.getNumberOfFailures();
}

} // namespace cpput

// Convenience macro to get main function.
#define CPPUT_TEST_MAIN                               \
int main(int argc, char* argv[]) {                    \
  if (argc == 2 && std::string(argv[1]) == "--xml") { \
    cpput::XmlResultWriter writer;                    \
    return ::cpput::runAllTests(writer);              \
  }                                                   \
  cpput::TextResultWriter writer;                     \
  return ::cpput::runAllTests(writer);                \
}

// ----------------------------------------------------------------------------
// Test Macros
// ----------------------------------------------------------------------------

/// Stand-alone test case.
///
#define TEST(group,name) \
class group##name##Test : public cpput::Test \
{ \
public: \
  group##name##Test() : cpput::Test(#group,#name) {} \
  virtual ~group##name##Test() {} \
private: \
  virtual void do_run(cpput::Result& testResult_); \
} group##name##TestInstance; \
inline void group##name##Test::do_run(cpput::Result& testResult_)

/// Test case with fixture.
///
#define TEST_F(group,name) \
class group##name##FixtureTest : public group { \
public: \
    void do_run(cpput::Result& testResult_); \
}; \
class group##name##Test : public cpput::Test { \
public: \
    group##name##Test() : Test(#group,#name) {} \
    virtual void do_run(cpput::Result& testResult_); \
} group##name##TestInstance; \
inline void group##name##Test::do_run(cpput::Result& testResult_) { \
  group##name##FixtureTest test; \
  test.do_run(testResult_); \
} \
inline void group##name##FixtureTest::do_run(cpput::Result& testResult_)

// ----------------------------------------------------------------------------
// Assertion Macros
// ----------------------------------------------------------------------------

#define ASSERT_TRUE(expression) \
{ \
  if (expression) \
    return; \
  testResult_.addFailure(__FILE__, __LINE__, #expression); \
}

#define ASSERT_FALSE(expression) ASSERT_TRUE(!(expression))

#define ASSERT_EQ(expected,actual) \
{ \
  if (!((expected) == (actual))) \
  { \
    testResult_.addFailure(__FILE__, __LINE__, expected, actual); \
    return; \
  } \
}

#define ASSERT_NEQ(expected,actual) \
{ \
  if (((expected) == (actual))) \
  { \
    testResult_.addFailure(__FILE__, __LINE__, expected, actual); \
    return; \
  } \
}

#define ASSERT_STREQ(expected,actual) { \
  if (!(std::string(expected) == std::string(actual))) \
  { \
    testResult_.addFailure(__FILE__, __LINE__, expected, actual); \
    return; \
  } \
}

#define ASSERT_NEAR(expected,actual,epsilon) \
{ \
  double actualTmp = actual; \
  double expectedTmp = expected; \
  double diff = expectedTmp - actualTmp; \
  if ((diff > epsilon) || (-diff > epsilon)) \
  { \
    testResult_.addFailure(__FILE__, __LINE__, expectedTmp, actualTmp); \
    return; \
  } \
}

#endif // CPPUT_TESTHARNESS_HPP
<commit_msg>Added license info into header file.<commit_after>/*
  Copyright (c) 2011-2014 Tommy Back

  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.
*/

/******************************************************************************
 *
 *  \brief    A light-weight and easy to use unit testing framework for C++
 *  \details  Header-only unit testing framework that makes unit testing easy
 *            and quick to set up.
 *  \version  0.2.0
 *  \author   Tommy Back
 *
 *
 *  Simply include this header file to get started.
 *
 *  \code
 *  #include <cpput/TestHarness.h>
 *  #include <Foo.h>
 *
 *  TEST(Foo, some_descriptive_name)
 *  {
 *    // Arrange
 *    Foo foo;
 *    // Act
 *    bool result = foo.isBar();
 *    // Assert
 *    ASSERT_TRUE(result);
 *  }
 *  \endcode
 *
 *  In case you want to keep a single file with tests that compile to an
 *  executable you can also add the main function to the end of the file.
 *  This is simple to do with the provided macro:
 *
 *  \code
 *  CPPUT_TEST_MAIN;
 *  \endcode
 *
 *  For larger test suits, it's recommended to group the tests per class
 *  in separate files and let the compiler combine them into a single
 *  executable which has a main.cpp file that only has the main function
 *  declared.
 *
 *  \example
 *  [Test_Foo.cpp]
 *
 *  \code
 *  #include <cpput/TestHarness.h>
 *  #include <Foo.h>
 *
 *  TEST(Foo, foo_bar_z)
 *  {
 *    ...
 *  \endcode
 *
 *  [main.cpp]
 *
 *  \code
 *  #include <cpput/TestHarness.h>
 *
 *  CPPUT_TEST_MAIN;
 *  \endcode
 *
 */

#ifndef CPPUT_TESTHARNESS_HPP
#define CPPUT_TESTHARNESS_HPP

#include <iostream>
#include <iomanip>
#include <string>
#include <sstream>
#include <ctime>

namespace cpput
{

struct ResultWriter
{
  virtual ~ResultWriter() {}

  virtual void startTest(const std::string& className, const std::string& name) = 0;
  virtual void endTest(bool success) = 0;

  virtual void failure(const std::string& filename, std::size_t line, const std::string& message) = 0;
  virtual int getNumberOfFailures() const = 0;
};

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

class TextResultWriter : public ResultWriter
{
public:
  TextResultWriter()
    : testCount_(0)
    , failures_(0)
  {
  }

  virtual ~TextResultWriter()
  {
    if (failures_ == 0)
    {
      std::cout << "\nAll tests pass.\n";
      return;
    }
    std::cout << "\n" << failures_ << " out of " << testCount_ << " tests failed.\n";
  }

  virtual void startTest(const std::string&, const std::string&)
  {
    testCount_++;
  }

  virtual void endTest(bool success)
  {
    if (success)
      std::cout << '.';
    else
      std::cout << 'F';
  }

  virtual void failure(const std::string& filename, std::size_t line, const std::string& message)
  {
    failures_++;
    std::cout << "Failure: " << filename << ", line " << line << ": " << message << '\n';
  }

  virtual int getNumberOfFailures() const { return failures_; }

private:
  int testCount_;
  int failures_;
};

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

class XmlResultWriter : public ResultWriter
{
public:
  XmlResultWriter()
    : startTime_(0)
  {
    std::cout << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
    std::cout << "<testsuite>\n";
  }

  virtual ~XmlResultWriter()
  {
    std::cout << "</testsuite>\n";
  }

  virtual void startTest(const std::string& className, const std::string& name)
  {
    startTime_ = std::clock();
    std::cout << "  <testcase classname=\""
              << className
              << "\" name=\""
              << name
              << "\" time=\"";
  }

  virtual void endTest(bool success)
  {
    if (success)
    {
      std::cout << static_cast<float>(std::clock()-startTime_)/CLOCKS_PER_SEC << "\"";
      std::cout << "/>\n";
    }
    else
      std::cout << "  </testcase>\n";
  }

  virtual void failure(const std::string& filename, std::size_t line, const std::string& message)
  {
    std::cout << static_cast<float>(std::clock()-startTime_)/CLOCKS_PER_SEC << "\"";
    std::cout << ">\n"
              << "    <failure>"
              << message
              << " in "
              << filename
              << ", line "
              << line
              << "</failure>\n";
    failureCount_++;
  }

  virtual int getNumberOfFailures() const
  {
    return failureCount_;
  }

private:
  std::clock_t startTime_;
  int          failureCount_;
};

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

struct Result
{
  Result(const std::string& testClassName,
         const std::string& testName,
         ResultWriter& out)
    : out_(out)
    , pass_(true)
  {
    out_.startTest(testClassName, testName);
  }

  ~Result()
  {
    out_.endTest(pass_);
  }

  template <typename T, typename U>
  void addFailure(const char* filename,
                  std::size_t line,
                  T expected,
                  U actual)
  {
    pass_ = false;
    std::stringstream ss;
    ss << std::setprecision(20)
       << "failed comparison, expected " << expected
       << " got " << actual << "\n";
    out_.failure(filename, line, ss.str());
  }

  void addFailure(const char* filename,
                  std::size_t line,
                  const char* message)
  {
    pass_ = false;
    out_.failure(filename, line, message);
  }

  ResultWriter& out_;
  bool          pass_;
};

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

class Repository;

class Test
{
  friend class Repository;

public:
  Test(const char* className, const char* name);
  virtual ~Test() {}

  void run(ResultWriter& out)
  {
    Result result(test_unit_class_name_, test_unit_name_, out);
    try
    {
      do_run(result);
    }
    catch (const std::exception& e)
    {
      result.addFailure(__FILE__, __LINE__, std::string("Unexpected exception: ").append(e.what()).c_str());
    }
    catch (...)
    {
      result.addFailure(__FILE__, __LINE__, "Unspecified exception!");
    }
  }

  Test* next() { return test_unit_next_; }

private:
  virtual void do_run(Result& testResult_) = 0;

private:
  std::string test_unit_class_name_;
  std::string test_unit_name_;
  Test*       test_unit_next_;
};

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

class Repository
{
public:
  static Repository& instance()
  {
    static Repository repo;
    return repo;
  }

  void add(Test* tc)
  {
    if (!tests_)
    {
      tests_ = tc;
      return;
    }

    // add as last
    Test* tmp = tests_;
    while (tmp->test_unit_next_)
      tmp = tmp->test_unit_next_;
    tmp->test_unit_next_ = tc;
  }

  Test* getTests() { return tests_; }

private:
  Repository() : tests_(0) {}
  Repository(const Repository& other);
  Repository& operator=(const Repository& rhs) const;

private:
  Test* tests_;
};

inline Test::Test(const char* className, const char* name)
  : test_unit_class_name_(className)
  , test_unit_name_(name)
  , test_unit_next_(0)
{
  Repository::instance().add(this);
}

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

inline int runAllTests(ResultWriter& writer)
{
  Test* c = Repository::instance().getTests();
  while (c)
  {
    c->run(writer);
    c = c->next();
  }
  return writer.getNumberOfFailures();
}

} // namespace cpput

// Convenience macro to get main function.
#define CPPUT_TEST_MAIN                               \
int main(int argc, char* argv[]) {                    \
  if (argc == 2 && std::string(argv[1]) == "--xml") { \
    cpput::XmlResultWriter writer;                    \
    return ::cpput::runAllTests(writer);              \
  }                                                   \
  cpput::TextResultWriter writer;                     \
  return ::cpput::runAllTests(writer);                \
}

// ----------------------------------------------------------------------------
// Test Macros
// ----------------------------------------------------------------------------

/// Stand-alone test case.
///
#define TEST(group,name) \
class group##name##Test : public cpput::Test \
{ \
public: \
  group##name##Test() : cpput::Test(#group,#name) {} \
  virtual ~group##name##Test() {} \
private: \
  virtual void do_run(cpput::Result& testResult_); \
} group##name##TestInstance; \
inline void group##name##Test::do_run(cpput::Result& testResult_)

/// Test case with fixture.
///
#define TEST_F(group,name) \
class group##name##FixtureTest : public group { \
public: \
    void do_run(cpput::Result& testResult_); \
}; \
class group##name##Test : public cpput::Test { \
public: \
    group##name##Test() : Test(#group,#name) {} \
    virtual void do_run(cpput::Result& testResult_); \
} group##name##TestInstance; \
inline void group##name##Test::do_run(cpput::Result& testResult_) { \
  group##name##FixtureTest test; \
  test.do_run(testResult_); \
} \
inline void group##name##FixtureTest::do_run(cpput::Result& testResult_)

// ----------------------------------------------------------------------------
// Assertion Macros
// ----------------------------------------------------------------------------

#define ASSERT_TRUE(expression) \
{ \
  if (expression) \
    return; \
  testResult_.addFailure(__FILE__, __LINE__, #expression); \
}

#define ASSERT_FALSE(expression) ASSERT_TRUE(!(expression))

#define ASSERT_EQ(expected,actual) \
{ \
  if (!((expected) == (actual))) \
  { \
    testResult_.addFailure(__FILE__, __LINE__, expected, actual); \
    return; \
  } \
}

#define ASSERT_NEQ(expected,actual) \
{ \
  if (((expected) == (actual))) \
  { \
    testResult_.addFailure(__FILE__, __LINE__, expected, actual); \
    return; \
  } \
}

#define ASSERT_STREQ(expected,actual) { \
  if (!(std::string(expected) == std::string(actual))) \
  { \
    testResult_.addFailure(__FILE__, __LINE__, expected, actual); \
    return; \
  } \
}

#define ASSERT_NEAR(expected,actual,epsilon) \
{ \
  double actualTmp = actual; \
  double expectedTmp = expected; \
  double diff = expectedTmp - actualTmp; \
  if ((diff > epsilon) || (-diff > epsilon)) \
  { \
    testResult_.addFailure(__FILE__, __LINE__, expectedTmp, actualTmp); \
    return; \
  } \
}

#endif // CPPUT_TESTHARNESS_HPP
<|endoftext|>


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

#include <limits.h>
#include <string.h>

#include <iostream>
#include <sstream>

#include "Group.h"
#include "Nebula.h"

const char * Group::table = "group_pool";

const char * Group::db_names =
        "oid, name, body, uid, gid, owner_u, group_u, other_u";

const char * Group::db_bootstrap = "CREATE TABLE IF NOT EXISTS group_pool ("
    "oid INTEGER PRIMARY KEY, name VARCHAR(128), body MEDIUMTEXT, uid INTEGER, "
    "gid INTEGER, owner_u INTEGER, group_u INTEGER, other_u INTEGER, "
    "UNIQUE(name))";

/* ************************************************************************ */
/* Group :: Database Access Functions                                       */
/* ************************************************************************ */

int Group::select(SqlDB * db)
{
    int rc;

    rc = PoolObjectSQL::select(db);

    if ( rc != 0 )
    {
        return rc;
    }

    return quota.select(oid, db);
}

/* -------------------------------------------------------------------------- */

int Group::select(SqlDB * db, const string& name, int uid)
{
    int rc;

    rc = PoolObjectSQL::select(db,name,uid);

    if ( rc != 0 )
    {
        return rc;
    }

    return quota.select(oid, db);
}

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

int Group::drop(SqlDB * db)
{
    int rc;

    rc = PoolObjectSQL::drop(db);

    if ( rc == 0 )
    {
        rc += quota.drop(db);
    }

    return rc;
}

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

int Group::insert(SqlDB *db, string& error_str)
{
    int rc;

    rc = insert_replace(db, false, error_str);

    if (rc == 0)
    {
        rc = quota.insert(oid, db, error_str);
    }

    return rc;
}

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

int Group::insert_replace(SqlDB *db, bool replace, string& error_str)
{
    ostringstream   oss;

    int    rc;
    string xml_body;

    char * sql_name;
    char * sql_xml;

    // Set oneadmin as the owner
    set_user(0,"");

    // Set the Group ID as the group it belongs to
    set_group(oid, name);

    // Update the Group

    sql_name = db->escape_str(name.c_str());

    if ( sql_name == 0 )
    {
        goto error_name;
    }

    sql_xml = db->escape_str(to_xml(xml_body).c_str());

    if ( sql_xml == 0 )
    {
        goto error_body;
    }

    if ( validate_xml(sql_xml) != 0 )
    {
        goto error_xml;
    }

    if ( replace )
    {
        oss << "REPLACE";
    }
    else
    {
        oss << "INSERT";
    }

    // Construct the SQL statement to Insert or Replace

    oss <<" INTO "<<table <<" ("<< db_names <<") VALUES ("
        <<          oid                 << ","
        << "'" <<   sql_name            << "',"
        << "'" <<   sql_xml             << "',"
        <<          uid                 << ","
        <<          gid                 << ","
        <<          owner_u             << ","
        <<          group_u             << ","
        <<          other_u             << ")";

    rc = db->exec(oss);

    db->free_str(sql_name);
    db->free_str(sql_xml);

    return rc;

error_xml:
    db->free_str(sql_name);
    db->free_str(sql_xml);

    error_str = "Error transforming the Group to XML.";

    goto error_common;

error_body:
    db->free_str(sql_name);
    goto error_generic;

error_name:
    goto error_generic;

error_generic:
    error_str = "Error inserting Group in DB.";
error_common:
    return -1;
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

string& Group::to_xml(string& xml) const
{
    return to_xml_extended(xml, false);
}

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

string& Group::to_xml_extended(string& xml) const
{
    return to_xml_extended(xml, true);
}

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

string& Group::to_xml_extended(string& xml, bool extended) const
{
    ostringstream   oss;
    string          collection_xml;
    string          admins_xml;
    string          template_xml;

    oss <<
    "<GROUP>"    <<
        "<ID>"   << oid  << "</ID>"        <<
        "<NAME>" << name << "</NAME>"      <<
        obj_template->to_xml(template_xml) <<
        users.to_xml(collection_xml) <<
        admins.to_xml(admins_xml);

    if (extended)
    {
        string quota_xml;
        string def_quota_xml;

        oss << quota.to_xml(quota_xml)
            << Nebula::instance().get_default_group_quota().to_xml(def_quota_xml);
    }

    oss << "</GROUP>";

    xml = oss.str();

    return xml;
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

int Group::from_xml(const string& xml)
{
    int rc = 0;
    vector<xmlNodePtr> content;
    vector<xmlNodePtr>::iterator it;

    // Initialize the internal XML object
    update_from_str(xml);

    // Get class base attributes
    rc += xpath(oid, "/GROUP/ID",   -1);
    rc += xpath(name,"/GROUP/NAME", "not_found");

    // Set oneadmin as the owner
    set_user(0,"");

    // Set the Group ID as the group it belongs to
    set_group(oid, name);

    // Set of IDs
    rc += users.from_xml(this, "/GROUP/");

    // Set of Admin IDs
    rc += admins.from_xml(this, "/GROUP/");

    // Get associated metadata for the group
    ObjectXML::get_nodes("/GROUP/TEMPLATE", content);

    if (content.empty())
    {
        return -1;
    }

    rc += obj_template->from_xml_node(content[0]);

    ObjectXML::free_nodes(content);
    content.clear();

    if (rc != 0)
    {
        return -1;
    }

    return 0;
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

int Group::add_admin(int user_id, string& error_msg)
{
    int rc;
    ostringstream oss;

    if ( users.contains(user_id) == false )
    {
        oss << "User " << user_id << " is not part of Group "
            << oid << ".";

        error_msg = oss.str();

        return -1;
    }

    rc = admins.add(user_id);

    if (rc == -1)
    {
        oss << "User " << user_id << " is already an administrator of Group "
            << oid << ".";

        error_msg = oss.str();

        return -1;
    }

    add_admin_rules(user_id);

    return 0;
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

void Group::add_admin_rules(int user_id)
{
    int     rc;
    string  error_msg;

    AclManager* aclm = Nebula::instance().get_aclm();

    // #<uid> USER/@<gid> USE+MANAGE+ADMIN+CREATE *
    rc = aclm->add_rule(
            AclRule::INDIVIDUAL_ID |
            user_id,

            PoolObjectSQL::USER |
            AclRule::GROUP_ID |
            oid,

            AuthRequest::USE |
            AuthRequest::MANAGE |
            AuthRequest::ADMIN |
            AuthRequest::CREATE,

            AclRule::ALL_ID,

            error_msg);

    if (rc < 0)
    {
        NebulaLog::log("GROUP",Log::ERROR,error_msg);
    }

    // #<uid> VM+NET+IMAGE+TEMPLATE+DOCUMENT+SECGROUP+VROUTER/@<gid> USE+MANAGE *
    rc = aclm->add_rule(
            AclRule::INDIVIDUAL_ID |
            user_id,

            PoolObjectSQL::VM |
            PoolObjectSQL::NET |
            PoolObjectSQL::IMAGE |
            PoolObjectSQL::TEMPLATE |
            PoolObjectSQL::DOCUMENT |
            PoolObjectSQL::SECGROUP |
            PoolObjectSQL::VROUTER |
            AclRule::GROUP_ID |
            oid,

            AuthRequest::USE |
            AuthRequest::MANAGE,

            AclRule::ALL_ID,

            error_msg);

    if (rc < 0)
    {
        NebulaLog::log("GROUP",Log::ERROR,error_msg);
    }
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

int Group::del_admin(int user_id, string& error_msg)
{
    int rc = admins.del(user_id);

    if (rc == -1)
    {
        ostringstream oss;
        oss << "User " << user_id << " is not an administrator of Group "
            << oid << ".";

        error_msg = oss.str();

        return -1;
    }

    del_admin_rules(user_id);

    return 0;
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

void Group::del_admin_rules(int user_id)
{
    int     rc;
    string  error_msg;

    AclManager* aclm = Nebula::instance().get_aclm();

    // #<uid> USER/@<gid> USE+MANAGE+ADMIN+CREATE *
    rc = aclm->del_rule(
            AclRule::INDIVIDUAL_ID |
            user_id,

            PoolObjectSQL::USER |
            AclRule::GROUP_ID |
            oid,

            AuthRequest::USE |
            AuthRequest::MANAGE |
            AuthRequest::ADMIN |
            AuthRequest::CREATE,

            AclRule::ALL_ID,

            error_msg);

    if (rc < 0)
    {
        NebulaLog::log("GROUP",Log::ERROR,error_msg);
    }

    // #<uid> VM+NET+IMAGE+TEMPLATE+DOCUMENT+SECGROUP+VROUTER/@<gid> USE+MANAGE *
    rc = aclm->del_rule(
            AclRule::INDIVIDUAL_ID |
            user_id,

            PoolObjectSQL::VM |
            PoolObjectSQL::NET |
            PoolObjectSQL::IMAGE |
            PoolObjectSQL::TEMPLATE |
            PoolObjectSQL::DOCUMENT |
            PoolObjectSQL::SECGROUP |
            PoolObjectSQL::VROUTER |
            AclRule::GROUP_ID |
            oid,

            AuthRequest::USE |
            AuthRequest::MANAGE,

            AclRule::ALL_ID,

            error_msg);

    if (rc < 0)
    {
        NebulaLog::log("GROUP",Log::ERROR,error_msg);
    }
}
<commit_msg>bug #4477: Add/del #<uid> VROUTER/* CREATE * for group admins by default<commit_after>/* ------------------------------------------------------------------------ */
/* Copyright 2002-2016, OpenNebula Project, OpenNebula Systems              */
/*                                                                          */
/* Licensed under the Apache License, Version 2.0 (the "License"); you may  */
/* not use this file except in compliance with the License. You may obtain  */
/* a copy of the License at                                                 */
/*                                                                          */
/* http://www.apache.org/licenses/LICENSE-2.0                               */
/*                                                                          */
/* Unless required by applicable law or agreed to in writing, software      */
/* distributed under the License is distributed on an "AS IS" BASIS,        */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
/* See the License for the specific language governing permissions and      */
/* limitations under the License.                                           */
/* ------------------------------------------------------------------------ */

#include <limits.h>
#include <string.h>

#include <iostream>
#include <sstream>

#include "Group.h"
#include "Nebula.h"

const char * Group::table = "group_pool";

const char * Group::db_names =
        "oid, name, body, uid, gid, owner_u, group_u, other_u";

const char * Group::db_bootstrap = "CREATE TABLE IF NOT EXISTS group_pool ("
    "oid INTEGER PRIMARY KEY, name VARCHAR(128), body MEDIUMTEXT, uid INTEGER, "
    "gid INTEGER, owner_u INTEGER, group_u INTEGER, other_u INTEGER, "
    "UNIQUE(name))";

/* ************************************************************************ */
/* Group :: Database Access Functions                                       */
/* ************************************************************************ */

int Group::select(SqlDB * db)
{
    int rc;

    rc = PoolObjectSQL::select(db);

    if ( rc != 0 )
    {
        return rc;
    }

    return quota.select(oid, db);
}

/* -------------------------------------------------------------------------- */

int Group::select(SqlDB * db, const string& name, int uid)
{
    int rc;

    rc = PoolObjectSQL::select(db,name,uid);

    if ( rc != 0 )
    {
        return rc;
    }

    return quota.select(oid, db);
}

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

int Group::drop(SqlDB * db)
{
    int rc;

    rc = PoolObjectSQL::drop(db);

    if ( rc == 0 )
    {
        rc += quota.drop(db);
    }

    return rc;
}

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

int Group::insert(SqlDB *db, string& error_str)
{
    int rc;

    rc = insert_replace(db, false, error_str);

    if (rc == 0)
    {
        rc = quota.insert(oid, db, error_str);
    }

    return rc;
}

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

int Group::insert_replace(SqlDB *db, bool replace, string& error_str)
{
    ostringstream   oss;

    int    rc;
    string xml_body;

    char * sql_name;
    char * sql_xml;

    // Set oneadmin as the owner
    set_user(0,"");

    // Set the Group ID as the group it belongs to
    set_group(oid, name);

    // Update the Group

    sql_name = db->escape_str(name.c_str());

    if ( sql_name == 0 )
    {
        goto error_name;
    }

    sql_xml = db->escape_str(to_xml(xml_body).c_str());

    if ( sql_xml == 0 )
    {
        goto error_body;
    }

    if ( validate_xml(sql_xml) != 0 )
    {
        goto error_xml;
    }

    if ( replace )
    {
        oss << "REPLACE";
    }
    else
    {
        oss << "INSERT";
    }

    // Construct the SQL statement to Insert or Replace

    oss <<" INTO "<<table <<" ("<< db_names <<") VALUES ("
        <<          oid                 << ","
        << "'" <<   sql_name            << "',"
        << "'" <<   sql_xml             << "',"
        <<          uid                 << ","
        <<          gid                 << ","
        <<          owner_u             << ","
        <<          group_u             << ","
        <<          other_u             << ")";

    rc = db->exec(oss);

    db->free_str(sql_name);
    db->free_str(sql_xml);

    return rc;

error_xml:
    db->free_str(sql_name);
    db->free_str(sql_xml);

    error_str = "Error transforming the Group to XML.";

    goto error_common;

error_body:
    db->free_str(sql_name);
    goto error_generic;

error_name:
    goto error_generic;

error_generic:
    error_str = "Error inserting Group in DB.";
error_common:
    return -1;
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

string& Group::to_xml(string& xml) const
{
    return to_xml_extended(xml, false);
}

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

string& Group::to_xml_extended(string& xml) const
{
    return to_xml_extended(xml, true);
}

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

string& Group::to_xml_extended(string& xml, bool extended) const
{
    ostringstream   oss;
    string          collection_xml;
    string          admins_xml;
    string          template_xml;

    oss <<
    "<GROUP>"    <<
        "<ID>"   << oid  << "</ID>"        <<
        "<NAME>" << name << "</NAME>"      <<
        obj_template->to_xml(template_xml) <<
        users.to_xml(collection_xml) <<
        admins.to_xml(admins_xml);

    if (extended)
    {
        string quota_xml;
        string def_quota_xml;

        oss << quota.to_xml(quota_xml)
            << Nebula::instance().get_default_group_quota().to_xml(def_quota_xml);
    }

    oss << "</GROUP>";

    xml = oss.str();

    return xml;
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

int Group::from_xml(const string& xml)
{
    int rc = 0;
    vector<xmlNodePtr> content;
    vector<xmlNodePtr>::iterator it;

    // Initialize the internal XML object
    update_from_str(xml);

    // Get class base attributes
    rc += xpath(oid, "/GROUP/ID",   -1);
    rc += xpath(name,"/GROUP/NAME", "not_found");

    // Set oneadmin as the owner
    set_user(0,"");

    // Set the Group ID as the group it belongs to
    set_group(oid, name);

    // Set of IDs
    rc += users.from_xml(this, "/GROUP/");

    // Set of Admin IDs
    rc += admins.from_xml(this, "/GROUP/");

    // Get associated metadata for the group
    ObjectXML::get_nodes("/GROUP/TEMPLATE", content);

    if (content.empty())
    {
        return -1;
    }

    rc += obj_template->from_xml_node(content[0]);

    ObjectXML::free_nodes(content);
    content.clear();

    if (rc != 0)
    {
        return -1;
    }

    return 0;
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

int Group::add_admin(int user_id, string& error_msg)
{
    int rc;
    ostringstream oss;

    if ( users.contains(user_id) == false )
    {
        oss << "User " << user_id << " is not part of Group "
            << oid << ".";

        error_msg = oss.str();

        return -1;
    }

    rc = admins.add(user_id);

    if (rc == -1)
    {
        oss << "User " << user_id << " is already an administrator of Group "
            << oid << ".";

        error_msg = oss.str();

        return -1;
    }

    add_admin_rules(user_id);

    return 0;
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

void Group::add_admin_rules(int user_id)
{
    string  error_msg;

    AclManager* aclm = Nebula::instance().get_aclm();

    // #<uid> USER/@<gid> USE+MANAGE+ADMIN+CREATE *
    if ( aclm->add_rule(
            AclRule::INDIVIDUAL_ID |
            user_id,

            PoolObjectSQL::USER |
            AclRule::GROUP_ID |
            oid,

            AuthRequest::USE |
            AuthRequest::MANAGE |
            AuthRequest::ADMIN |
            AuthRequest::CREATE,

            AclRule::ALL_ID,

            error_msg) < 0 )
    {
        NebulaLog::log("GROUP",Log::ERROR,error_msg);
    }

    // #<uid> VM+NET+IMAGE+TEMPLATE+DOCUMENT+SECGROUP+VROUTER/@<gid> USE+MANAGE *
    if ( aclm->add_rule(
            AclRule::INDIVIDUAL_ID |
            user_id,

            PoolObjectSQL::VM |
            PoolObjectSQL::NET |
            PoolObjectSQL::IMAGE |
            PoolObjectSQL::TEMPLATE |
            PoolObjectSQL::DOCUMENT |
            PoolObjectSQL::SECGROUP |
            PoolObjectSQL::VROUTER |
            AclRule::GROUP_ID |
            oid,

            AuthRequest::USE |
            AuthRequest::MANAGE,

            AclRule::ALL_ID,

            error_msg) < 0 )
    {
        NebulaLog::log("GROUP",Log::ERROR,error_msg);
    }

    // #<uid> VROUTER/* CREATE *
    if ( aclm->add_rule(
            AclRule::INDIVIDUAL_ID |
            user_id,

            AclRule::ALL_ID |
            PoolObjectSQL::VROUTER,

            AuthRequest::CREATE,

            AclRule::ALL_ID,

            error_msg) < 0 )
    {
        NebulaLog::log("GROUP",Log::ERROR,error_msg);
    }
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

int Group::del_admin(int user_id, string& error_msg)
{
    int rc = admins.del(user_id);

    if (rc == -1)
    {
        ostringstream oss;
        oss << "User " << user_id << " is not an administrator of Group "
            << oid << ".";

        error_msg = oss.str();

        return -1;
    }

    del_admin_rules(user_id);

    return 0;
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

void Group::del_admin_rules(int user_id)
{
    string  error_msg;

    AclManager *aclm = Nebula::instance().get_aclm();

    // #<uid> USER/@<gid> USE+MANAGE+ADMIN+CREATE *
    if ( aclm->del_rule(
            AclRule::INDIVIDUAL_ID |
            user_id,

            PoolObjectSQL::USER |
            AclRule::GROUP_ID |
            oid,

            AuthRequest::USE |
            AuthRequest::MANAGE |
            AuthRequest::ADMIN |
            AuthRequest::CREATE,

            AclRule::ALL_ID,

            error_msg) < 0)
    {
        NebulaLog::log("GROUP",Log::ERROR,error_msg);
    }

    // #<uid> VM+NET+IMAGE+TEMPLATE+DOCUMENT+SECGROUP+VROUTER/@<gid> USE+MANAGE *
    if ( aclm->del_rule(
            AclRule::INDIVIDUAL_ID |
            user_id,

            PoolObjectSQL::VM |
            PoolObjectSQL::NET |
            PoolObjectSQL::IMAGE |
            PoolObjectSQL::TEMPLATE |
            PoolObjectSQL::DOCUMENT |
            PoolObjectSQL::SECGROUP |
            PoolObjectSQL::VROUTER |
            AclRule::GROUP_ID |
            oid,

            AuthRequest::USE |
            AuthRequest::MANAGE,

            AclRule::ALL_ID,

            error_msg) < 0)
    {
        NebulaLog::log("GROUP",Log::ERROR,error_msg);
    }

    // #<uid> VROUTER/* CREATE *
    if ( aclm->del_rule(
            AclRule::INDIVIDUAL_ID |
            user_id,

            AclRule::ALL_ID |
            PoolObjectSQL::VROUTER,

            AuthRequest::CREATE,

            AclRule::ALL_ID,

            error_msg) < 0 )
    {
        NebulaLog::log("GROUP",Log::ERROR,error_msg);
    }
}
<|endoftext|>


<commit_before><commit_msg>Fix counter miscounting<commit_after><|endoftext|>


<commit_before>/***
Copyright (C) 2013 Aniket Deole <aniket.deole@gmail.com>
This program is free software: you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License version 2.1, as published
by the Free Software Foundation.

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

You should have received a copy of the GNU General Public License along
with this program.  If not, see <http://www.gnu.org/licenses/>.
***/

#include <gtkmm/box.h>
#include <gtkmm/widget.h>

#include <iostream>

#include "maintoolbar.hh"

MainToolbar::MainToolbar () {

 //Create the toolbar and add it to a container widget:
  Gtk::ToolButton* button = Gtk::manage(new Gtk::ToolButton());
  // TODO Change this later to set_icon_widget
//  button->set_icon_name("dialog-cancel");
  button->set_label ("Close");
  button->signal_clicked().connect(sigc::mem_fun(*this,
              &MainToolbar::exitNotify) );
  add(*button);

  Gtk::SeparatorToolItem* sti = Gtk::manage (new Gtk::SeparatorToolItem ());
  sti->set_expand (false);
  sti->set_draw (true);
  add (*sti);

  button = Gtk::manage(new Gtk::ToolButton());
  button->set_size_request (40, 40);
  button->set_label ("New Note");
  button->signal_clicked().connect(sigc::mem_fun(*this,
              &MainToolbar::newNote) );
  add(*button);

  button = Gtk::manage(new Gtk::ToolButton());
  button->set_size_request (40, 40);
  button->set_label ("New Notebook");
  button->signal_clicked().connect(sigc::mem_fun(*this,
              &MainToolbar::newNotebook) );
  add(*button);

  sti = Gtk::manage (new Gtk::SeparatorToolItem ());
  sti->set_expand (true);
  sti->set_can_focus (false);
  sti->set_use_action_appearance (false);
  sti->set_visible (true);
  add (*sti);

  Gtk::ToolItem* searchEntryContainer = Gtk::manage (new Gtk::ToolItem ());

  searchEntry = Gtk::manage (new Gtk::Entry ());
  searchEntry->set_text ("");
  searchEntry->set_icon_from_icon_name ("system-search");
  searchEntry->signal_changed ().connect (sigc::mem_fun (*this,
            &MainToolbar::searchCallback));
  searchEntry->signal_activate ().connect (sigc::mem_fun (*this,
            &MainToolbar::searchEntryClicked));
  searchEntryActive = false;
  addCss (searchEntry, "searchEntry", ".searchEntry { color: #888; \n}\n");
  searchEntryContainer->add (*searchEntry);
  add (*searchEntryContainer);

  button = Gtk::manage(new Gtk::ToolButton());
  button->set_size_request (40, 40);
  button->set_label ("Maximize");
  add (*button);

	Glib::RefPtr<Gtk::StyleContext> sc = get_style_context();
	sc->add_class("primary-toolbar");

  show_all ();
}

MainToolbar::~MainToolbar () {

}

void MainToolbar::exitNotify () {
  exit (0);
}

void MainToolbar::newNote () {
  app->nlpv->newNote ();
}

void MainToolbar::newNotebook () {
  app->lpv->newNotebook ();
}

void MainToolbar::searchCallback () {
  if (searchEntry->get_text().empty ()){
    return;
  }
  app->nlpv->noteSearch (searchEntry->get_text ());
}

void MainToolbar::searchEntryClicked () {
  if (!searchEntryActive) {
   searchEntry->set_text ("");
   searchEntryActive = true;
  }
}<commit_msg>Fixed issue with window not being draggable.<commit_after>/***
Copyright (C) 2013 Aniket Deole <aniket.deole@gmail.com>
This program is free software: you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License version 2.1, as published
by the Free Software Foundation.

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

You should have received a copy of the GNU General Public License along
with this program.  If not, see <http://www.gnu.org/licenses/>.
***/

#include <gtkmm/box.h>
#include <gtkmm/widget.h>

#include <iostream>

#include "maintoolbar.hh"

MainToolbar::MainToolbar () {

 //Create the toolbar and add it to a container widget:
  Gtk::ToolButton* button = Gtk::manage(new Gtk::ToolButton());
  // TODO Change this later to set_icon_widget
//  button->set_icon_name("dialog-cancel");
  button->set_label ("Close");
  button->signal_clicked().connect(sigc::mem_fun(*this,
              &MainToolbar::exitNotify) );
  add(*button);

  Gtk::SeparatorToolItem* sti = Gtk::manage (new Gtk::SeparatorToolItem ());
  sti->set_expand (false);
  sti->set_draw (true);
  add (*sti);

  button = Gtk::manage(new Gtk::ToolButton());
  button->set_size_request (40, 40);
  button->set_label ("New Note");
  button->signal_clicked().connect(sigc::mem_fun(*this,
              &MainToolbar::newNote) );
  add(*button);

  button = Gtk::manage(new Gtk::ToolButton());
  button->set_size_request (40, 40);
  button->set_label ("New Notebook");
  button->signal_clicked().connect(sigc::mem_fun(*this,
              &MainToolbar::newNotebook) );
  add(*button);

  Gtk::ToolItem* ti = Gtk::manage (new Gtk::ToolItem ());
  ti->set_expand (true);
  add (*ti);

  Gtk::ToolItem* searchEntryContainer = Gtk::manage (new Gtk::ToolItem ());

  searchEntry = Gtk::manage (new Gtk::Entry ());
  searchEntry->set_text ("");
  searchEntry->set_icon_from_icon_name ("system-search");
  searchEntry->signal_changed ().connect (sigc::mem_fun (*this,
            &MainToolbar::searchCallback));
  searchEntry->signal_activate ().connect (sigc::mem_fun (*this,
            &MainToolbar::searchEntryClicked));
  searchEntryActive = false;
  addCss (searchEntry, "searchEntry", ".searchEntry { color: #888; \n}\n");
  searchEntryContainer->add (*searchEntry);
  add (*searchEntryContainer);

  button = Gtk::manage(new Gtk::ToolButton());
  button->set_size_request (40, 40);
  button->set_label ("Maximize");
  add (*button);

	Glib::RefPtr<Gtk::StyleContext> sc = get_style_context();
	sc->add_class("primary-toolbar");

  show_all ();
}

MainToolbar::~MainToolbar () {

}

void MainToolbar::exitNotify () {
  exit (0);
}

void MainToolbar::newNote () {
  app->nlpv->newNote ();
}

void MainToolbar::newNotebook () {
  app->lpv->newNotebook ();
}

void MainToolbar::searchCallback () {
  if (searchEntry->get_text().empty ()){
    return;
  }
  app->nlpv->noteSearch (searchEntry->get_text ());
}

void MainToolbar::searchEntryClicked () {
  if (!searchEntryActive) {
   searchEntry->set_text ("");
   searchEntryActive = true;
  }
}<|endoftext|>


<commit_before>/*
 * Main Send File Transfer Window
 *
 * Copyright (C) 2011 David Edmundson <kde@davidedmundson.co.uk>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <KFileItem>
#include <KFileItemList>
#include <KIO/PreviewJob>
#include <KApplication>
#include <KCmdLineArgs>
#include <KMimeType>
#include <KDebug>
#include <KMessageBox>
#include <KPixmapSequence>
#include <KPixmapSequenceOverlayPainter>
#include <KDE/KIO/PreviewJob>

#include <QAbstractItemDelegate>
#include <QPainter>
#include <QRect>
#include <QStyle>
#include <QDebug>
#include <QAbstractButton>

#include <TelepathyQt4/AccountManager>
#include <TelepathyQt4/PendingChannelRequest>
#include <TelepathyQt4/PendingReady>

#include "flat-model-proxy.h"

#include "common/models/accounts-model.h"
#include "common/models/accounts-filter-model.h"
#include "common/models/contact-model-item.h"

//FIXME, copy and paste the approver code for loading this from a config file into this, the contact list and the chat handler.
#define PREFERRED_FILETRANSFER_HANDLER "org.freedesktop.Telepathy.Client.KDE.FileTransfer"

class ContactGridDelegate : public QAbstractItemDelegate {
public:
    ContactGridDelegate(QObject *parent);
    void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
    QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const;
};

ContactGridDelegate::ContactGridDelegate(QObject *parent)
    : QAbstractItemDelegate(parent)
{

}

void ContactGridDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    QStyle *style = QApplication::style();
    int textHeight = option.fontMetrics.height()*2;

    style->drawPrimitive(QStyle::PE_PanelItemViewItem, &option, painter);

    QRect avatarRect = option.rect.adjusted(0,0,0,-textHeight);
    QRect textRect = option.rect.adjusted(0,option.rect.height()-textHeight,0,-3);

    QPixmap avatar = index.data(Qt::DecorationRole).value<QPixmap>();
    if (avatar.isNull()) {
        avatar = KIcon("im-user-online").pixmap(QSize(70,70));
    }

    //resize larger avatars
    if (avatar.width() > 80 || avatar.height()> 80) {
        avatar = avatar.scaled(QSize(80,80), Qt::KeepAspectRatio);
        //draw leaving paddings on smaller (or non square) avatars
    }
    style->drawItemPixmap(painter, avatarRect, Qt::AlignCenter, avatar);

    QTextOption textOption;
    textOption.setAlignment(Qt::AlignCenter);
    textOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
    painter->drawText(textRect, index.data().toString(), textOption);

}

QSize ContactGridDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    Q_UNUSED(index);
    int textHeight = option.fontMetrics.height()*2;
    return QSize(84, 80 + textHeight + 3);
}

MainWindow::MainWindow(const KUrl &url, QWidget *parent) :
    QWidget(parent),
    ui(new Ui::MainWindow),
    m_accountsModel(0)
{
    Tp::registerTypes();

    ui->setupUi(this);
    setWindowTitle(i18n("Send file - %1", url.fileName());

    kDebug() << KApplication::arguments();

    ui->fileNameLabel->setText(url.fileName());
    m_busyOverlay = new KPixmapSequenceOverlayPainter(this);
    m_busyOverlay->setSequence(KPixmapSequence("process-working", 22));
    m_busyOverlay->setWidget(ui->filePreview);
    m_busyOverlay->start();

    KFileItem file(KFileItem::Unknown, KFileItem::Unknown, url);
    QStringList availablePlugins = KIO::PreviewJob::availablePlugins();
    KIO::PreviewJob* job = KIO::filePreview(KFileItemList() << file, QSize(280, 280), &availablePlugins);
    job->setOverlayIconAlpha(0);
    job->setScaleType(KIO::PreviewJob::Unscaled);
    connect(job, SIGNAL(gotPreview(KFileItem,QPixmap)),
            this, SLOT(onPreviewLoaded(KFileItem,QPixmap)));
    connect(job, SIGNAL(failed(KFileItem)),
            this, SLOT(onPreviewFailed(KFileItem)));

    Tp::AccountFactoryPtr  accountFactory = Tp::AccountFactory::create(QDBusConnection::sessionBus(),
                                                                       Tp::Features() << Tp::Account::FeatureCore
                                                                       << Tp::Account::FeatureAvatar
                                                                       << Tp::Account::FeatureProtocolInfo
                                                                       << Tp::Account::FeatureProfile);

    Tp::ConnectionFactoryPtr connectionFactory = Tp::ConnectionFactory::create(QDBusConnection::sessionBus(),
                                                                               Tp::Features() << Tp::Connection::FeatureCore
                                                                               << Tp::Connection::FeatureRosterGroups
                                                                               << Tp::Connection::FeatureRoster
                                                                               << Tp::Connection::FeatureSelfContact);

    Tp::ContactFactoryPtr contactFactory = Tp::ContactFactory::create(Tp::Features()  << Tp::Contact::FeatureAlias
                                                                      << Tp::Contact::FeatureAvatarData
                                                                      << Tp::Contact::FeatureSimplePresence
                                                                      << Tp::Contact::FeatureCapabilities);

    Tp::ChannelFactoryPtr channelFactory = Tp::ChannelFactory::create(QDBusConnection::sessionBus());

    m_accountManager = Tp::AccountManager::create(QDBusConnection::sessionBus(),
                                                  accountFactory,
                                                  connectionFactory,
                                                  channelFactory,
                                                  contactFactory);

    connect(m_accountManager->becomeReady(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(onAccountManagerReady()));

    connect(ui->buttonBox, SIGNAL(accepted()), SLOT(onDialogAccepted()));
    connect(ui->buttonBox, SIGNAL(rejected()), SLOT(close()));
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::onAccountManagerReady()
{
    m_accountsModel = new AccountsModel(m_accountManager, this);
    AccountsFilterModel *filterModel = new AccountsFilterModel(this);
    filterModel->setSourceModel(m_accountsModel);
    filterModel->setShowOfflineUsers(false);
    FlatModelProxy *flatProxyModel = new FlatModelProxy(filterModel);

    ui->listView->setModel(flatProxyModel);
    ui->listView->setItemDelegate(new ContactGridDelegate(this));
}

void MainWindow::onDialogAccepted()
{
    // don't do anytghing if no contact has been selected
    if (!ui->listView->currentIndex().isValid()) {
        // show message box?
        return;
    }

    ContactModelItem *contactModelItem = ui->listView->currentIndex().data(AccountsModel::ItemRole).value<ContactModelItem*>();
    Tp::ContactPtr contact = contactModelItem->contact();
    Tp::AccountPtr sendingAccount = m_accountsModel->accountForContactItem(contactModelItem);

    if (sendingAccount.isNull()) {
        kDebug() << "sending account: NULL";
    } else {
        kDebug() << "Account is: " << sendingAccount->displayName();
        kDebug() << "sending to: " << contact->alias();
    }

    // start sending file
    QString filePath (KCmdLineArgs::parsedArgs()->arg(0));
    qDebug() << "FILE TO SEND: " << filePath;

    Tp::FileTransferChannelCreationProperties fileTransferProperties(filePath, KMimeType::findByFileContent(filePath)->name());

    Tp::PendingChannelRequest* channelRequest = sendingAccount->createFileTransfer(contact,
                                                                                fileTransferProperties,
                                                                                QDateTime::currentDateTime(),
                                                                                PREFERRED_FILETRANSFER_HANDLER);

    connect(channelRequest, SIGNAL(finished(Tp::PendingOperation*)), SLOT(slotFileTransferFinished(Tp::PendingOperation*)));

    //disable the buttons
    foreach(QAbstractButton* button, ui->buttonBox->buttons()) {
        button->setEnabled(false);
    }
}

void MainWindow::slotFileTransferFinished(Tp::PendingOperation* op)
{
    if (op->isError()) {
        //FIXME map to human readable strings.
        QString errorMsg(op->errorName() + ": " + op->errorMessage());
        kDebug() << "ERROR!: " << errorMsg;
        KMessageBox::error(this, i18n("Failed to send file"), i18n("File Transfer Failed"));
        close();
    } else {
        kDebug() << "Transfer started";
        // now I can close the dialog
        close();
    }
}

void MainWindow::onPreviewLoaded(const KFileItem& item, const QPixmap& preview)
{
    Q_UNUSED(item);
    ui->filePreview->setPixmap(preview);
    m_busyOverlay->stop();
}

void MainWindow::onPreviewFailed(const KFileItem& item)
{
    kWarning() << "Loading thumb failed" << item.name();
    ui->filePreview->setPixmap(KIconLoader::global()->loadIcon(item.iconName(), KIconLoader::Desktop, 128));
    m_busyOverlay->stop();
}
<commit_msg>Fix compile<commit_after>/*
 * Main Send File Transfer Window
 *
 * Copyright (C) 2011 David Edmundson <kde@davidedmundson.co.uk>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <KFileItem>
#include <KFileItemList>
#include <KIO/PreviewJob>
#include <KApplication>
#include <KCmdLineArgs>
#include <KMimeType>
#include <KDebug>
#include <KMessageBox>
#include <KPixmapSequence>
#include <KPixmapSequenceOverlayPainter>
#include <KDE/KIO/PreviewJob>

#include <QAbstractItemDelegate>
#include <QPainter>
#include <QRect>
#include <QStyle>
#include <QDebug>
#include <QAbstractButton>

#include <TelepathyQt4/AccountManager>
#include <TelepathyQt4/PendingChannelRequest>
#include <TelepathyQt4/PendingReady>

#include "flat-model-proxy.h"

#include "common/models/accounts-model.h"
#include "common/models/accounts-filter-model.h"
#include "common/models/contact-model-item.h"

//FIXME, copy and paste the approver code for loading this from a config file into this, the contact list and the chat handler.
#define PREFERRED_FILETRANSFER_HANDLER "org.freedesktop.Telepathy.Client.KDE.FileTransfer"

class ContactGridDelegate : public QAbstractItemDelegate {
public:
    ContactGridDelegate(QObject *parent);
    void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
    QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const;
};

ContactGridDelegate::ContactGridDelegate(QObject *parent)
    : QAbstractItemDelegate(parent)
{

}

void ContactGridDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    QStyle *style = QApplication::style();
    int textHeight = option.fontMetrics.height()*2;

    style->drawPrimitive(QStyle::PE_PanelItemViewItem, &option, painter);

    QRect avatarRect = option.rect.adjusted(0,0,0,-textHeight);
    QRect textRect = option.rect.adjusted(0,option.rect.height()-textHeight,0,-3);

    QPixmap avatar = index.data(Qt::DecorationRole).value<QPixmap>();
    if (avatar.isNull()) {
        avatar = KIcon("im-user-online").pixmap(QSize(70,70));
    }

    //resize larger avatars
    if (avatar.width() > 80 || avatar.height()> 80) {
        avatar = avatar.scaled(QSize(80,80), Qt::KeepAspectRatio);
        //draw leaving paddings on smaller (or non square) avatars
    }
    style->drawItemPixmap(painter, avatarRect, Qt::AlignCenter, avatar);

    QTextOption textOption;
    textOption.setAlignment(Qt::AlignCenter);
    textOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
    painter->drawText(textRect, index.data().toString(), textOption);

}

QSize ContactGridDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    Q_UNUSED(index);
    int textHeight = option.fontMetrics.height()*2;
    return QSize(84, 80 + textHeight + 3);
}

MainWindow::MainWindow(const KUrl &url, QWidget *parent) :
    QWidget(parent),
    ui(new Ui::MainWindow),
    m_accountsModel(0)
{
    Tp::registerTypes();

    ui->setupUi(this);
    setWindowTitle(i18n("Send file - %1", url.fileName()));

    kDebug() << KApplication::arguments();

    ui->fileNameLabel->setText(url.fileName());
    m_busyOverlay = new KPixmapSequenceOverlayPainter(this);
    m_busyOverlay->setSequence(KPixmapSequence("process-working", 22));
    m_busyOverlay->setWidget(ui->filePreview);
    m_busyOverlay->start();

    KFileItem file(KFileItem::Unknown, KFileItem::Unknown, url);
    QStringList availablePlugins = KIO::PreviewJob::availablePlugins();
    KIO::PreviewJob* job = KIO::filePreview(KFileItemList() << file, QSize(280, 280), &availablePlugins);
    job->setOverlayIconAlpha(0);
    job->setScaleType(KIO::PreviewJob::Unscaled);
    connect(job, SIGNAL(gotPreview(KFileItem,QPixmap)),
            this, SLOT(onPreviewLoaded(KFileItem,QPixmap)));
    connect(job, SIGNAL(failed(KFileItem)),
            this, SLOT(onPreviewFailed(KFileItem)));

    Tp::AccountFactoryPtr  accountFactory = Tp::AccountFactory::create(QDBusConnection::sessionBus(),
                                                                       Tp::Features() << Tp::Account::FeatureCore
                                                                       << Tp::Account::FeatureAvatar
                                                                       << Tp::Account::FeatureProtocolInfo
                                                                       << Tp::Account::FeatureProfile);

    Tp::ConnectionFactoryPtr connectionFactory = Tp::ConnectionFactory::create(QDBusConnection::sessionBus(),
                                                                               Tp::Features() << Tp::Connection::FeatureCore
                                                                               << Tp::Connection::FeatureRosterGroups
                                                                               << Tp::Connection::FeatureRoster
                                                                               << Tp::Connection::FeatureSelfContact);

    Tp::ContactFactoryPtr contactFactory = Tp::ContactFactory::create(Tp::Features()  << Tp::Contact::FeatureAlias
                                                                      << Tp::Contact::FeatureAvatarData
                                                                      << Tp::Contact::FeatureSimplePresence
                                                                      << Tp::Contact::FeatureCapabilities);

    Tp::ChannelFactoryPtr channelFactory = Tp::ChannelFactory::create(QDBusConnection::sessionBus());

    m_accountManager = Tp::AccountManager::create(QDBusConnection::sessionBus(),
                                                  accountFactory,
                                                  connectionFactory,
                                                  channelFactory,
                                                  contactFactory);

    connect(m_accountManager->becomeReady(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(onAccountManagerReady()));

    connect(ui->buttonBox, SIGNAL(accepted()), SLOT(onDialogAccepted()));
    connect(ui->buttonBox, SIGNAL(rejected()), SLOT(close()));
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::onAccountManagerReady()
{
    m_accountsModel = new AccountsModel(m_accountManager, this);
    AccountsFilterModel *filterModel = new AccountsFilterModel(this);
    filterModel->setSourceModel(m_accountsModel);
    filterModel->setShowOfflineUsers(false);
    FlatModelProxy *flatProxyModel = new FlatModelProxy(filterModel);

    ui->listView->setModel(flatProxyModel);
    ui->listView->setItemDelegate(new ContactGridDelegate(this));
}

void MainWindow::onDialogAccepted()
{
    // don't do anytghing if no contact has been selected
    if (!ui->listView->currentIndex().isValid()) {
        // show message box?
        return;
    }

    ContactModelItem *contactModelItem = ui->listView->currentIndex().data(AccountsModel::ItemRole).value<ContactModelItem*>();
    Tp::ContactPtr contact = contactModelItem->contact();
    Tp::AccountPtr sendingAccount = m_accountsModel->accountForContactItem(contactModelItem);

    if (sendingAccount.isNull()) {
        kDebug() << "sending account: NULL";
    } else {
        kDebug() << "Account is: " << sendingAccount->displayName();
        kDebug() << "sending to: " << contact->alias();
    }

    // start sending file
    QString filePath (KCmdLineArgs::parsedArgs()->arg(0));
    qDebug() << "FILE TO SEND: " << filePath;

    Tp::FileTransferChannelCreationProperties fileTransferProperties(filePath, KMimeType::findByFileContent(filePath)->name());

    Tp::PendingChannelRequest* channelRequest = sendingAccount->createFileTransfer(contact,
                                                                                fileTransferProperties,
                                                                                QDateTime::currentDateTime(),
                                                                                PREFERRED_FILETRANSFER_HANDLER);

    connect(channelRequest, SIGNAL(finished(Tp::PendingOperation*)), SLOT(slotFileTransferFinished(Tp::PendingOperation*)));

    //disable the buttons
    foreach(QAbstractButton* button, ui->buttonBox->buttons()) {
        button->setEnabled(false);
    }
}

void MainWindow::slotFileTransferFinished(Tp::PendingOperation* op)
{
    if (op->isError()) {
        //FIXME map to human readable strings.
        QString errorMsg(op->errorName() + ": " + op->errorMessage());
        kDebug() << "ERROR!: " << errorMsg;
        KMessageBox::error(this, i18n("Failed to send file"), i18n("File Transfer Failed"));
        close();
    } else {
        kDebug() << "Transfer started";
        // now I can close the dialog
        close();
    }
}

void MainWindow::onPreviewLoaded(const KFileItem& item, const QPixmap& preview)
{
    Q_UNUSED(item);
    ui->filePreview->setPixmap(preview);
    m_busyOverlay->stop();
}

void MainWindow::onPreviewFailed(const KFileItem& item)
{
    kWarning() << "Loading thumb failed" << item.name();
    ui->filePreview->setPixmap(KIconLoader::global()->loadIcon(item.iconName(), KIconLoader::Desktop, 128));
    m_busyOverlay->stop();
}
<|endoftext|>


<commit_before>#include <QtWidgets>
#include "mainwindow.h"
#include <fts_fuzzy_match.h>
#include <glob.h>
#include <string>
#include <map>
#include <database.h>

Window::Window(QWidget *parent) : QWidget(parent)
{
    // Initalise database
    db.setDatabaseName("recipes.db");

    // Initialise widgets
    searchBox = new SearchBox();
    searchBox->setPlaceholderText("Search for recipes");
    recipeBox = new QComboBox();
    QStringList recipeCategories;
    recipeCategories << "All Recipes" << "Beef" << "Chicken" << "Dessert" << "Lamb" << "Pork" << "Seafood" << "Turkey" << "Veggie";
    recipeBox->addItems(recipeCategories);
    createRecipeList();
    numResults = new QLabel();

    // Set layout
    QGridLayout *mainLayout = new QGridLayout;
    mainLayout->addWidget(searchBox, 0, 0, 1, 6);
    mainLayout->addWidget(numResults, 0, 6, 1, 1);
    mainLayout->addWidget(recipeBox, 0, 7, 1, 1);
    mainLayout->addWidget(recipeList, 1, 0, 1, 8);
    setLayout(mainLayout);

    // Set window paramters
    setWindowTitle(tr("Find Recipes"));
    setMinimumSize(600, 400);

    // Set signals
    connect(recipeList, &QListWidget::itemDoubleClicked, this, &Window::openFile);
    connect(searchBox, SIGNAL(inputText(QString)), this, SLOT(updateRecipesDiplay(QString)));
    connect(searchBox, SIGNAL(returnPressed()), recipeList, SLOT(setFocus()));
    connect(recipeBox, SIGNAL(currentTextChanged(QString)), searchBox, SLOT(recipeFiterChanged(QString)));

    // Populate list on start up
    updateRecipesDiplay("");

    db_ops::update_database(&db);
}

// Get list of files according to glob patternn
QStringList globVector(const std::string& pattern){
    glob_t glob_result;
    glob(pattern.c_str(),GLOB_TILDE,NULL,&glob_result);
    QStringList files;
    for(unsigned int i=0; i<glob_result.gl_pathc; ++i){
        files << QString(glob_result.gl_pathv[i]);
    }
    globfree(&glob_result);
    return files;
}

void SearchBox::recipeFiterChanged(QString newFilter){
    // When the recipe filter changes, emit this signal to call updateRecipeDisplay
    emit inputText(text());
}

void SearchBox::keyPressEvent(QKeyEvent *evt){
    QLineEdit::keyPressEvent(evt);
    // When the search changes, emit this signal to call updateRecipeDisplay
    emit inputText(text());
}

void Window::updateRecipesDiplay(QString searchText){
    recipeList->clear();

    QList<QListWidgetItem*> recipes = getRecipeList(searchText);
    for (int i=0; i<recipes.size(); ++i){
        recipeList->addItem(recipes[i]);
    }

    if(searchText.isEmpty()){
        recipeList->sortItems();
    }

    QString text = QString("%1 recipes").arg(recipes.size());
    if (recipes.size() == 1){
        text = "1 recipe";
    }
    numResults->setText(text);
}

QList<QListWidgetItem*> Window::getRecipeList(QString searchText){
    QList<QListWidgetItem*> recipes;
    if (searchText.isEmpty()) {
        recipes = getAllRecipes();
    }else{
        recipes = getMatchingRecipes(searchText);
    }
    return recipes;
}

QList<QListWidgetItem*> Window::getAllRecipes(){
    QList<QListWidgetItem*> recipes;

    // Open database and execute query
    db.open();
    QSqlQuery query = QSqlQuery();
    query.exec("select TITLE, IMG_PATH, FILE_PATH from RECIPES");

    while(query.next()){
        // Extract info from query results
        QString title = query.value(0).toString();
        QString img_path = query.value(1).toString();
        QString file_path = query.value(2).toString();

        // Create QListWidgetItems
        QListWidgetItem *recipe = new QListWidgetItem;
        recipe->setText(title);
        recipe->setData(Qt::UserRole, file_path);

        QImage *img = new QImage();
        bool loaded = img->load(img_path);
        if (loaded){
            recipe->setIcon(QPixmap::fromImage(*img));
        }else{
            // If image doesn't exist, use placeholder image
            bool loaded = img->load("./Images/Placeholder.jpg");
            if (loaded){
                recipe->setIcon(QPixmap::fromImage(*img));
            }
        }
        recipes.append(recipe);
    }
    db.close();
    return recipes;
}

QList<QListWidgetItem*> Window::getMatchingRecipes(QString searchText){
    QList<QListWidgetItem*> recipes;

    // Get matching recipes and their scores
    std::map<double, QString> matchingRecipes = findMatches(searchText);
    // Build QListWidgetItems and add to QList
    // By default the map should be in ascending order, so use reverse iterator to get highest matches first
    for (auto iter = matchingRecipes.rbegin(); iter != matchingRecipes.rend(); ++iter){
        QString path_name = iter->second;
        QString img_path = "Images/" + path_name.split('/')[1].replace(" ", "_").replace(".md", ".jpg");

        QListWidgetItem *recipe = new QListWidgetItem;
        recipe->setText(path_name.split('/')[1].replace(".md", ""));
        recipe->setData(Qt::UserRole, path_name);

        QImage *img = new QImage();
        bool loaded = img->load(img_path);
        if (loaded){
            recipe->setIcon(QPixmap::fromImage(*img));
        }else{
            // If image doesn't exist, use placeholder image
            bool loaded = img->load("./Images/Placeholder.jpg");
            if (loaded){
                recipe->setIcon(QPixmap::fromImage(*img));
            }
        }
        recipes.append(recipe);
    }

    return recipes;
}

std::map<double, QString> Window::findMatches(QString text)
{
    // Get all files in current recipe filter
    std::string pattern = "*/*.md";
    if(recipeBox->currentText() != "All Recipes"){
        pattern = recipeBox->currentText().toStdString() + "/*.md";
    }
    QStringList files = globVector(pattern);
    // Get matching files and their scores
    std::map<double, QString> matchingFiles;
    std::string txtstr = text.toStdString();
    for (int i=0; i<files.size(); ++i){
        int score;
        std::string filestr = files[i].split('/')[1].toStdString();
        if (fts::fuzzy_match_score(txtstr.c_str(), filestr.c_str(), score)){
            // If a map entry already has the current score, increase score by 0.01.
            double dbscore = (double)score;
            if (matchingFiles.count(dbscore) > 0){
                dbscore += 0.01;
            }
            matchingFiles[dbscore] = files[i];
        }
    }
    return matchingFiles;
}

void Window::createRecipeList()
{
    recipeList = new QListWidget();
    recipeList->setViewMode(QListView::IconMode);
    recipeList->setIconSize(QSize(267, 150));
    recipeList->setGridSize(QSize(280, 185));
    recipeList->setWordWrap(true);
    recipeList->setTextElideMode(Qt::ElideNone);
}

void Window::openFile(QListWidgetItem *recipe)
{
    // Read hidden data to find full file path
    QString path = recipe->data(Qt::UserRole).toString();
    QDesktopServices::openUrl(QUrl::fromLocalFile(currentDir.absoluteFilePath(path)));
}

void Window::resizeEvent(QResizeEvent *event){
    int iconWidth, iconHeight, gridWidth, gridHeight, columns;
    double gridRatio = 280.0/185.0;
    double iconRatio = 267.0/150.0;
    QSize recipeListSize = recipeList->size();

    if(recipeListSize.width()<=578){
        // Set defaults for minimum size
        columns = 2;
        iconWidth = 267;
        iconHeight = 150;
        gridWidth = 280;
        gridHeight = 185;
    }else{
        // Icons should never go larger than default, so set number of columns to round up
        columns = ceil(recipeListSize.width()/280.0);
        // Width of grid is widget_width/columns, with extra width removed to allow for scrollbar
        gridWidth = int(recipeListSize.width()/columns) - ceil(18.0/columns);
        // Calculate other parameters based on ratios of default values.
        gridHeight = int(gridWidth/gridRatio);
        iconWidth = gridWidth - 13;
        iconHeight = int(iconWidth/iconRatio);
    }

    recipeList->setIconSize(QSize(iconWidth, iconHeight));
    recipeList->setGridSize(QSize(gridWidth, gridHeight));
}

<commit_msg>Remove line of code used to test database update function<commit_after>#include <QtWidgets>
#include "mainwindow.h"
#include <fts_fuzzy_match.h>
#include <glob.h>
#include <string>
#include <map>
#include <database.h>

Window::Window(QWidget *parent) : QWidget(parent)
{
    // Initalise database
    db.setDatabaseName("recipes.db");

    // Initialise widgets
    searchBox = new SearchBox();
    searchBox->setPlaceholderText("Search for recipes");
    recipeBox = new QComboBox();
    QStringList recipeCategories;
    recipeCategories << "All Recipes" << "Beef" << "Chicken" << "Dessert" << "Lamb" << "Pork" << "Seafood" << "Turkey" << "Veggie";
    recipeBox->addItems(recipeCategories);
    createRecipeList();
    numResults = new QLabel();

    // Set layout
    QGridLayout *mainLayout = new QGridLayout;
    mainLayout->addWidget(searchBox, 0, 0, 1, 6);
    mainLayout->addWidget(numResults, 0, 6, 1, 1);
    mainLayout->addWidget(recipeBox, 0, 7, 1, 1);
    mainLayout->addWidget(recipeList, 1, 0, 1, 8);
    setLayout(mainLayout);

    // Set window paramters
    setWindowTitle(tr("Find Recipes"));
    setMinimumSize(600, 400);

    // Set signals
    connect(recipeList, &QListWidget::itemDoubleClicked, this, &Window::openFile);
    connect(searchBox, SIGNAL(inputText(QString)), this, SLOT(updateRecipesDiplay(QString)));
    connect(searchBox, SIGNAL(returnPressed()), recipeList, SLOT(setFocus()));
    connect(recipeBox, SIGNAL(currentTextChanged(QString)), searchBox, SLOT(recipeFiterChanged(QString)));

    // Populate list on start up
    updateRecipesDiplay("");
}

// Get list of files according to glob patternn
QStringList globVector(const std::string& pattern){
    glob_t glob_result;
    glob(pattern.c_str(),GLOB_TILDE,NULL,&glob_result);
    QStringList files;
    for(unsigned int i=0; i<glob_result.gl_pathc; ++i){
        files << QString(glob_result.gl_pathv[i]);
    }
    globfree(&glob_result);
    return files;
}

void SearchBox::recipeFiterChanged(QString newFilter){
    // When the recipe filter changes, emit this signal to call updateRecipeDisplay
    emit inputText(text());
}

void SearchBox::keyPressEvent(QKeyEvent *evt){
    QLineEdit::keyPressEvent(evt);
    // When the search changes, emit this signal to call updateRecipeDisplay
    emit inputText(text());
}

void Window::updateRecipesDiplay(QString searchText){
    recipeList->clear();

    QList<QListWidgetItem*> recipes = getRecipeList(searchText);
    for (int i=0; i<recipes.size(); ++i){
        recipeList->addItem(recipes[i]);
    }

    if(searchText.isEmpty()){
        recipeList->sortItems();
    }

    QString text = QString("%1 recipes").arg(recipes.size());
    if (recipes.size() == 1){
        text = "1 recipe";
    }
    numResults->setText(text);
}

QList<QListWidgetItem*> Window::getRecipeList(QString searchText){
    QList<QListWidgetItem*> recipes;
    if (searchText.isEmpty()) {
        recipes = getAllRecipes();
    }else{
        recipes = getMatchingRecipes(searchText);
    }
    return recipes;
}

QList<QListWidgetItem*> Window::getAllRecipes(){
    QList<QListWidgetItem*> recipes;

    // Open database and execute query
    db.open();
    QSqlQuery query = QSqlQuery();
    query.exec("select TITLE, IMG_PATH, FILE_PATH from RECIPES");

    while(query.next()){
        // Extract info from query results
        QString title = query.value(0).toString();
        QString img_path = query.value(1).toString();
        QString file_path = query.value(2).toString();

        // Create QListWidgetItems
        QListWidgetItem *recipe = new QListWidgetItem;
        recipe->setText(title);
        recipe->setData(Qt::UserRole, file_path);

        QImage *img = new QImage();
        bool loaded = img->load(img_path);
        if (loaded){
            recipe->setIcon(QPixmap::fromImage(*img));
        }else{
            // If image doesn't exist, use placeholder image
            bool loaded = img->load("./Images/Placeholder.jpg");
            if (loaded){
                recipe->setIcon(QPixmap::fromImage(*img));
            }
        }
        recipes.append(recipe);
    }
    db.close();
    return recipes;
}

QList<QListWidgetItem*> Window::getMatchingRecipes(QString searchText){
    QList<QListWidgetItem*> recipes;

    // Get matching recipes and their scores
    std::map<double, QString> matchingRecipes = findMatches(searchText);
    // Build QListWidgetItems and add to QList
    // By default the map should be in ascending order, so use reverse iterator to get highest matches first
    for (auto iter = matchingRecipes.rbegin(); iter != matchingRecipes.rend(); ++iter){
        QString path_name = iter->second;
        QString img_path = "Images/" + path_name.split('/')[1].replace(" ", "_").replace(".md", ".jpg");

        QListWidgetItem *recipe = new QListWidgetItem;
        recipe->setText(path_name.split('/')[1].replace(".md", ""));
        recipe->setData(Qt::UserRole, path_name);

        QImage *img = new QImage();
        bool loaded = img->load(img_path);
        if (loaded){
            recipe->setIcon(QPixmap::fromImage(*img));
        }else{
            // If image doesn't exist, use placeholder image
            bool loaded = img->load("./Images/Placeholder.jpg");
            if (loaded){
                recipe->setIcon(QPixmap::fromImage(*img));
            }
        }
        recipes.append(recipe);
    }

    return recipes;
}

std::map<double, QString> Window::findMatches(QString text)
{
    // Get all files in current recipe filter
    std::string pattern = "*/*.md";
    if(recipeBox->currentText() != "All Recipes"){
        pattern = recipeBox->currentText().toStdString() + "/*.md";
    }
    QStringList files = globVector(pattern);
    // Get matching files and their scores
    std::map<double, QString> matchingFiles;
    std::string txtstr = text.toStdString();
    for (int i=0; i<files.size(); ++i){
        int score;
        std::string filestr = files[i].split('/')[1].toStdString();
        if (fts::fuzzy_match_score(txtstr.c_str(), filestr.c_str(), score)){
            // If a map entry already has the current score, increase score by 0.01.
            double dbscore = (double)score;
            if (matchingFiles.count(dbscore) > 0){
                dbscore += 0.01;
            }
            matchingFiles[dbscore] = files[i];
        }
    }
    return matchingFiles;
}

void Window::createRecipeList()
{
    recipeList = new QListWidget();
    recipeList->setViewMode(QListView::IconMode);
    recipeList->setIconSize(QSize(267, 150));
    recipeList->setGridSize(QSize(280, 185));
    recipeList->setWordWrap(true);
    recipeList->setTextElideMode(Qt::ElideNone);
}

void Window::openFile(QListWidgetItem *recipe)
{
    // Read hidden data to find full file path
    QString path = recipe->data(Qt::UserRole).toString();
    QDesktopServices::openUrl(QUrl::fromLocalFile(currentDir.absoluteFilePath(path)));
}

void Window::resizeEvent(QResizeEvent *event){
    int iconWidth, iconHeight, gridWidth, gridHeight, columns;
    double gridRatio = 280.0/185.0;
    double iconRatio = 267.0/150.0;
    QSize recipeListSize = recipeList->size();

    if(recipeListSize.width()<=578){
        // Set defaults for minimum size
        columns = 2;
        iconWidth = 267;
        iconHeight = 150;
        gridWidth = 280;
        gridHeight = 185;
    }else{
        // Icons should never go larger than default, so set number of columns to round up
        columns = ceil(recipeListSize.width()/280.0);
        // Width of grid is widget_width/columns, with extra width removed to allow for scrollbar
        gridWidth = int(recipeListSize.width()/columns) - ceil(18.0/columns);
        // Calculate other parameters based on ratios of default values.
        gridHeight = int(gridWidth/gridRatio);
        iconWidth = gridWidth - 13;
        iconHeight = int(iconWidth/iconRatio);
    }

    recipeList->setIconSize(QSize(iconWidth, iconHeight));
    recipeList->setGridSize(QSize(gridWidth, gridHeight));
}

<|endoftext|>