<commit_before>//===--- InitHeaderSearch.cpp - Initialize header search paths ----------*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the InitHeaderSearch class.
//
//===----------------------------------------------------------------------===//

#include "clang/Frontend/InitHeaderSearch.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/LangOptions.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/System/Path.h"
#include "llvm/Config/config.h"
#include <cstdio>
#include <vector>
using namespace clang;

void InitHeaderSearch::AddPath(const std::string &Path, IncludeDirGroup Group,
                               bool isCXXAware, bool isUserSupplied,
                               bool isFramework, bool IgnoreSysRoot) {
  assert(!Path.empty() && "can't handle empty path here");
  FileManager &FM = Headers.getFileMgr();

  // Compute the actual path, taking into consideration -isysroot.
  llvm::SmallString<256> MappedPath;

  // Handle isysroot.
  if (Group == System && !IgnoreSysRoot) {
    // FIXME: Portability.  This should be a sys::Path interface, this doesn't
    // handle things like C:\ right, nor win32 \\network\device\blah.
    if (isysroot.size() != 1 || isysroot[0] != '/') // Add isysroot if present.
      MappedPath.append(isysroot.begin(), isysroot.end());
  }

  MappedPath.append(Path.begin(), Path.end());

  // Compute the DirectoryLookup type.
  SrcMgr::CharacteristicKind Type;
  if (Group == Quoted || Group == Angled)
    Type = SrcMgr::C_User;
  else if (isCXXAware)
    Type = SrcMgr::C_System;
  else
    Type = SrcMgr::C_ExternCSystem;

  // If the directory exists, add it.
  if (const DirectoryEntry *DE = FM.getDirectory(&MappedPath[0],
                                                 &MappedPath[0]+
                                                 MappedPath.size())) {
    IncludeGroup[Group].push_back(DirectoryLookup(DE, Type, isUserSupplied,
                                                  isFramework));
    return;
  }

  // Check to see if this is an apple-style headermap (which are not allowed to
  // be frameworks).
  if (!isFramework) {
    if (const FileEntry *FE = FM.getFile(&MappedPath[0],
                                         &MappedPath[0]+MappedPath.size())) {
      if (const HeaderMap *HM = Headers.CreateHeaderMap(FE)) {
        // It is a headermap, add it to the search path.
        IncludeGroup[Group].push_back(DirectoryLookup(HM, Type,isUserSupplied));
        return;
      }
    }
  }

  if (Verbose)
    fprintf(stderr, "ignoring nonexistent directory \"%s\"\n",
            MappedPath.c_str());
}

void InitHeaderSearch::AddEnvVarPaths(const char *Name) {
  const char* at = getenv(Name);
  if (!at || *at == 0) // Empty string should not add '.' path.
    return;

  const char* delim = strchr(at, llvm::sys::PathSeparator);
  while (delim != 0) {
    if (delim-at == 0)
      AddPath(".", Angled, false, true, false);
    else
      AddPath(std::string(at, std::string::size_type(delim-at)), Angled, false,
              true, false);
    at = delim + 1;
    delim = strchr(at, llvm::sys::PathSeparator);
  }
  if (*at == 0)
    AddPath(".", Angled, false, true, false);
  else
    AddPath(at, Angled, false, true, false);
}

void InitHeaderSearch::AddDefaultSystemIncludePaths(const LangOptions &Lang) {
  // FIXME: temporary hack: hard-coded paths.
  // FIXME: get these from the target?

#ifdef LLVM_ON_WIN32
  if (Lang.CPlusPlus) {
    // Mingw32 GCC version 4
    AddPath("c:/mingw/lib/gcc/mingw32/4.3.0/include/c++",
            System, true, false, false);
    AddPath("c:/mingw/lib/gcc/mingw32/4.3.0/include/c++/mingw32",
            System, true, false, false);
    AddPath("c:/mingw/lib/gcc/mingw32/4.3.0/include/c++/backward",
            System, true, false, false);
  }

  // Mingw32 GCC version 4
  AddPath("C:/mingw/include", System, false, false, false);
#else

  if (Lang.CPlusPlus) {
    AddPath("/usr/include/c++/4.2.1", System, true, false, false);
    AddPath("/usr/include/c++/4.2.1/i686-apple-darwin10", System, true, false,
        false);
    AddPath("/usr/include/c++/4.2.1/backward", System, true, false, false);

    AddPath("/usr/include/c++/4.0.0", System, true, false, false);
    AddPath("/usr/include/c++/4.0.0/i686-apple-darwin8", System, true, false,
        false);
    AddPath("/usr/include/c++/4.0.0/backward", System, true, false, false);

    // Ubuntu 7.10 - Gutsy Gibbon
    AddPath("/usr/include/c++/4.1.3", System, true, false, false);
    AddPath("/usr/include/c++/4.1.3/i486-linux-gnu", System, true, false,
        false);
    AddPath("/usr/include/c++/4.1.3/backward", System, true, false, false);

    // Fedora 8
    AddPath("/usr/include/c++/4.1.2", System, true, false, false);
    AddPath("/usr/include/c++/4.1.2/i386-redhat-linux", System, true, false,
        false);
    AddPath("/usr/include/c++/4.1.2/backward", System, true, false, false);

    // Fedora 9
    AddPath("/usr/include/c++/4.3.0", System, true, false, false);
    AddPath("/usr/include/c++/4.3.0/i386-redhat-linux", System, true, false,
        false);
    AddPath("/usr/include/c++/4.3.0/backward", System, true, false, false);

    // Fedora 10
    AddPath("/usr/include/c++/4.3.2", System, true, false, false);
    AddPath("/usr/include/c++/4.3.2/i386-redhat-linux", System, true, false,
        false);
    AddPath("/usr/include/c++/4.3.2/backward", System, true, false, false);

    // Arch Linux 2008-06-24
    AddPath("/usr/include/c++/4.3.1", System, true, false, false);
    AddPath("/usr/include/c++/4.3.1/i686-pc-linux-gnu", System, true, false,
        false);
    AddPath("/usr/include/c++/4.3.1/backward", System, true, false, false);
    AddPath("/usr/include/c++/4.3.1/x86_64-unknown-linux-gnu", System, true,
        false, false);

    // Gentoo x86 stable
    AddPath("/usr/lib/gcc/i686-pc-linux-gnu/4.1.2/include/g++-v4", System,
            true, false, false);
    AddPath("/usr/lib/gcc/i686-pc-linux-gnu/4.1.2/include/g++-v4/"
            "i686-pc-linux-gnu", System, true, false, false);
    AddPath("/usr/lib/gcc/i686-pc-linux-gnu/4.1.2/include/g++-v4/backward",
            System, true, false, false);

    // DragonFly
    AddPath("/usr/include/c++/4.1", System, true, false, false);

    // FreeBSD
    AddPath("/usr/include/c++/4.2", System, true, false, false);
  }

  AddPath("/usr/local/include", System, false, false, false);

  AddPath("/usr/include", System, false, false, false);
  AddPath("/System/Library/Frameworks", System, true, false, true);
  AddPath("/Library/Frameworks", System, true, false, true);
#endif
}

void InitHeaderSearch::AddDefaultEnvVarPaths(const LangOptions &Lang) {
  AddEnvVarPaths("CPATH");
  if (Lang.CPlusPlus && Lang.ObjC1)
    AddEnvVarPaths("OBJCPLUS_INCLUDE_PATH");
  else if (Lang.CPlusPlus)
    AddEnvVarPaths("CPLUS_INCLUDE_PATH");
  else if (Lang.ObjC1)
    AddEnvVarPaths("OBJC_INCLUDE_PATH");
  else
    AddEnvVarPaths("C_INCLUDE_PATH");
}

/// RemoveDuplicates - If there are duplicate directory entries in the specified
/// search list, remove the later (dead) ones.
static void RemoveDuplicates(std::vector<DirectoryLookup> &SearchList,
                             bool Verbose) {
  llvm::SmallPtrSet<const DirectoryEntry *, 8> SeenDirs;
  llvm::SmallPtrSet<const DirectoryEntry *, 8> SeenFrameworkDirs;
  llvm::SmallPtrSet<const HeaderMap *, 8> SeenHeaderMaps;
  for (unsigned i = 0; i != SearchList.size(); ++i) {
    unsigned DirToRemove = i;

    const DirectoryLookup &CurEntry = SearchList[i];

    if (CurEntry.isNormalDir()) {
      // If this isn't the first time we've seen this dir, remove it.
      if (SeenDirs.insert(CurEntry.getDir()))
        continue;
    } else if (CurEntry.isFramework()) {
      // If this isn't the first time we've seen this framework dir, remove it.
      if (SeenFrameworkDirs.insert(CurEntry.getFrameworkDir()))
        continue;
    } else {
      assert(CurEntry.isHeaderMap() && "Not a headermap or normal dir?");
      // If this isn't the first time we've seen this headermap, remove it.
      if (SeenHeaderMaps.insert(CurEntry.getHeaderMap()))
        continue;
    }

    // If we have a normal #include dir/framework/headermap that is shadowed
    // later in the chain by a system include location, we actually want to
    // ignore the user's request and drop the user dir... keeping the system
    // dir.  This is weird, but required to emulate GCC's search path correctly.
    //
    // Since dupes of system dirs are rare, just rescan to find the original
    // that we're nuking instead of using a DenseMap.
    if (CurEntry.getDirCharacteristic() != SrcMgr::C_User) {
      // Find the dir that this is the same of.
      unsigned FirstDir;
      for (FirstDir = 0; ; ++FirstDir) {
        assert(FirstDir != i && "Didn't find dupe?");

        const DirectoryLookup &SearchEntry = SearchList[FirstDir];

        // If these are different lookup types, then they can't be the dupe.
        if (SearchEntry.getLookupType() != CurEntry.getLookupType())
          continue;

        bool isSame;
        if (CurEntry.isNormalDir())
          isSame = SearchEntry.getDir() == CurEntry.getDir();
        else if (CurEntry.isFramework())
          isSame = SearchEntry.getFrameworkDir() == CurEntry.getFrameworkDir();
        else {
          assert(CurEntry.isHeaderMap() && "Not a headermap or normal dir?");
          isSame = SearchEntry.getHeaderMap() == CurEntry.getHeaderMap();
        }

        if (isSame)
          break;
      }

      // If the first dir in the search path is a non-system dir, zap it
      // instead of the system one.
      if (SearchList[FirstDir].getDirCharacteristic() == SrcMgr::C_User)
        DirToRemove = FirstDir;
    }

    if (Verbose) {
      fprintf(stderr, "ignoring duplicate directory \"%s\"\n",
              CurEntry.getName());
      if (DirToRemove != i)
        fprintf(stderr, "  as it is a non-system directory that duplicates"
                " a system directory\n");
    }

    // This is reached if the current entry is a duplicate.  Remove the
    // DirToRemove (usually the current dir).
    SearchList.erase(SearchList.begin()+DirToRemove);
    --i;
  }
}

void InitHeaderSearch::Realize() {
  // Concatenate ANGLE+SYSTEM+AFTER chains together into SearchList.
  std::vector<DirectoryLookup> SearchList;
  SearchList = IncludeGroup[Angled];
  SearchList.insert(SearchList.end(), IncludeGroup[System].begin(),
                    IncludeGroup[System].end());
  SearchList.insert(SearchList.end(), IncludeGroup[After].begin(),
                    IncludeGroup[After].end());
  RemoveDuplicates(SearchList, Verbose);
  RemoveDuplicates(IncludeGroup[Quoted], Verbose);

  // Prepend QUOTED list on the search list.
  SearchList.insert(SearchList.begin(), IncludeGroup[Quoted].begin(),
                    IncludeGroup[Quoted].end());

  bool DontSearchCurDir = false;  // TODO: set to true if -I- is set?
  Headers.SetSearchPaths(SearchList, IncludeGroup[Quoted].size(),
                         DontSearchCurDir);

  // If verbose, print the list of directories that will be searched.
  if (Verbose) {
    fprintf(stderr, "#include \"...\" search starts here:\n");
    unsigned QuotedIdx = IncludeGroup[Quoted].size();
    for (unsigned i = 0, e = SearchList.size(); i != e; ++i) {
      if (i == QuotedIdx)
        fprintf(stderr, "#include <...> search starts here:\n");
      const char *Name = SearchList[i].getName();
      const char *Suffix;
      if (SearchList[i].isNormalDir())
        Suffix = "";
      else if (SearchList[i].isFramework())
        Suffix = " (framework directory)";
      else {
        assert(SearchList[i].isHeaderMap() && "Unknown DirectoryLookup");
        Suffix = " (headermap)";
      }
      fprintf(stderr, " %s%s\n", Name, Suffix);
    }
    fprintf(stderr, "End of search list.\n");
  }
}

<commit_msg>Search path for 64-bit Ubuntu Linux, from Anders Johnsen<commit_after>//===--- InitHeaderSearch.cpp - Initialize header search paths ----------*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the InitHeaderSearch class.
//
//===----------------------------------------------------------------------===//

#include "clang/Frontend/InitHeaderSearch.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/LangOptions.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/System/Path.h"
#include "llvm/Config/config.h"
#include <cstdio>
#include <vector>
using namespace clang;

void InitHeaderSearch::AddPath(const std::string &Path, IncludeDirGroup Group,
                               bool isCXXAware, bool isUserSupplied,
                               bool isFramework, bool IgnoreSysRoot) {
  assert(!Path.empty() && "can't handle empty path here");
  FileManager &FM = Headers.getFileMgr();

  // Compute the actual path, taking into consideration -isysroot.
  llvm::SmallString<256> MappedPath;

  // Handle isysroot.
  if (Group == System && !IgnoreSysRoot) {
    // FIXME: Portability.  This should be a sys::Path interface, this doesn't
    // handle things like C:\ right, nor win32 \\network\device\blah.
    if (isysroot.size() != 1 || isysroot[0] != '/') // Add isysroot if present.
      MappedPath.append(isysroot.begin(), isysroot.end());
  }

  MappedPath.append(Path.begin(), Path.end());

  // Compute the DirectoryLookup type.
  SrcMgr::CharacteristicKind Type;
  if (Group == Quoted || Group == Angled)
    Type = SrcMgr::C_User;
  else if (isCXXAware)
    Type = SrcMgr::C_System;
  else
    Type = SrcMgr::C_ExternCSystem;

  // If the directory exists, add it.
  if (const DirectoryEntry *DE = FM.getDirectory(&MappedPath[0],
                                                 &MappedPath[0]+
                                                 MappedPath.size())) {
    IncludeGroup[Group].push_back(DirectoryLookup(DE, Type, isUserSupplied,
                                                  isFramework));
    return;
  }

  // Check to see if this is an apple-style headermap (which are not allowed to
  // be frameworks).
  if (!isFramework) {
    if (const FileEntry *FE = FM.getFile(&MappedPath[0],
                                         &MappedPath[0]+MappedPath.size())) {
      if (const HeaderMap *HM = Headers.CreateHeaderMap(FE)) {
        // It is a headermap, add it to the search path.
        IncludeGroup[Group].push_back(DirectoryLookup(HM, Type,isUserSupplied));
        return;
      }
    }
  }

  if (Verbose)
    fprintf(stderr, "ignoring nonexistent directory \"%s\"\n",
            MappedPath.c_str());
}

void InitHeaderSearch::AddEnvVarPaths(const char *Name) {
  const char* at = getenv(Name);
  if (!at || *at == 0) // Empty string should not add '.' path.
    return;

  const char* delim = strchr(at, llvm::sys::PathSeparator);
  while (delim != 0) {
    if (delim-at == 0)
      AddPath(".", Angled, false, true, false);
    else
      AddPath(std::string(at, std::string::size_type(delim-at)), Angled, false,
              true, false);
    at = delim + 1;
    delim = strchr(at, llvm::sys::PathSeparator);
  }
  if (*at == 0)
    AddPath(".", Angled, false, true, false);
  else
    AddPath(at, Angled, false, true, false);
}

void InitHeaderSearch::AddDefaultSystemIncludePaths(const LangOptions &Lang) {
  // FIXME: temporary hack: hard-coded paths.
  // FIXME: get these from the target?

#ifdef LLVM_ON_WIN32
  if (Lang.CPlusPlus) {
    // Mingw32 GCC version 4
    AddPath("c:/mingw/lib/gcc/mingw32/4.3.0/include/c++",
            System, true, false, false);
    AddPath("c:/mingw/lib/gcc/mingw32/4.3.0/include/c++/mingw32",
            System, true, false, false);
    AddPath("c:/mingw/lib/gcc/mingw32/4.3.0/include/c++/backward",
            System, true, false, false);
  }

  // Mingw32 GCC version 4
  AddPath("C:/mingw/include", System, false, false, false);
#else

  if (Lang.CPlusPlus) {
    AddPath("/usr/include/c++/4.2.1", System, true, false, false);
    AddPath("/usr/include/c++/4.2.1/i686-apple-darwin10", System, true, false,
        false);
    AddPath("/usr/include/c++/4.2.1/backward", System, true, false, false);

    AddPath("/usr/include/c++/4.0.0", System, true, false, false);
    AddPath("/usr/include/c++/4.0.0/i686-apple-darwin8", System, true, false,
        false);
    AddPath("/usr/include/c++/4.0.0/backward", System, true, false, false);

    // Ubuntu 7.10 - Gutsy Gibbon
    AddPath("/usr/include/c++/4.1.3", System, true, false, false);
    AddPath("/usr/include/c++/4.1.3/i486-linux-gnu", System, true, false,
        false);
    AddPath("/usr/include/c++/4.1.3/backward", System, true, false, false);

    // Ubuntu 9.04
    AddPath("/usr/include/c++/4.3.3", System, true, false, false);
    AddPath("/usr/include/c++/4.3.3/x86_64-linux-gnu/", System, true, false,
        false);
    AddPath("/usr/include/c++/4.3.3/backward", System, true, false, false);

    // Fedora 8
    AddPath("/usr/include/c++/4.1.2", System, true, false, false);
    AddPath("/usr/include/c++/4.1.2/i386-redhat-linux", System, true, false,
        false);
    AddPath("/usr/include/c++/4.1.2/backward", System, true, false, false);

    // Fedora 9
    AddPath("/usr/include/c++/4.3.0", System, true, false, false);
    AddPath("/usr/include/c++/4.3.0/i386-redhat-linux", System, true, false,
        false);
    AddPath("/usr/include/c++/4.3.0/backward", System, true, false, false);

    // Fedora 10
    AddPath("/usr/include/c++/4.3.2", System, true, false, false);
    AddPath("/usr/include/c++/4.3.2/i386-redhat-linux", System, true, false,
        false);
    AddPath("/usr/include/c++/4.3.2/backward", System, true, false, false);

    // Arch Linux 2008-06-24
    AddPath("/usr/include/c++/4.3.1", System, true, false, false);
    AddPath("/usr/include/c++/4.3.1/i686-pc-linux-gnu", System, true, false,
        false);
    AddPath("/usr/include/c++/4.3.1/backward", System, true, false, false);
    AddPath("/usr/include/c++/4.3.1/x86_64-unknown-linux-gnu", System, true,
        false, false);

    // Gentoo x86 stable
    AddPath("/usr/lib/gcc/i686-pc-linux-gnu/4.1.2/include/g++-v4", System,
            true, false, false);
    AddPath("/usr/lib/gcc/i686-pc-linux-gnu/4.1.2/include/g++-v4/"
            "i686-pc-linux-gnu", System, true, false, false);
    AddPath("/usr/lib/gcc/i686-pc-linux-gnu/4.1.2/include/g++-v4/backward",
            System, true, false, false);

    // DragonFly
    AddPath("/usr/include/c++/4.1", System, true, false, false);

    // FreeBSD
    AddPath("/usr/include/c++/4.2", System, true, false, false);
  }

  AddPath("/usr/local/include", System, false, false, false);

  AddPath("/usr/include", System, false, false, false);
  AddPath("/System/Library/Frameworks", System, true, false, true);
  AddPath("/Library/Frameworks", System, true, false, true);
#endif
}

void InitHeaderSearch::AddDefaultEnvVarPaths(const LangOptions &Lang) {
  AddEnvVarPaths("CPATH");
  if (Lang.CPlusPlus && Lang.ObjC1)
    AddEnvVarPaths("OBJCPLUS_INCLUDE_PATH");
  else if (Lang.CPlusPlus)
    AddEnvVarPaths("CPLUS_INCLUDE_PATH");
  else if (Lang.ObjC1)
    AddEnvVarPaths("OBJC_INCLUDE_PATH");
  else
    AddEnvVarPaths("C_INCLUDE_PATH");
}

/// RemoveDuplicates - If there are duplicate directory entries in the specified
/// search list, remove the later (dead) ones.
static void RemoveDuplicates(std::vector<DirectoryLookup> &SearchList,
                             bool Verbose) {
  llvm::SmallPtrSet<const DirectoryEntry *, 8> SeenDirs;
  llvm::SmallPtrSet<const DirectoryEntry *, 8> SeenFrameworkDirs;
  llvm::SmallPtrSet<const HeaderMap *, 8> SeenHeaderMaps;
  for (unsigned i = 0; i != SearchList.size(); ++i) {
    unsigned DirToRemove = i;

    const DirectoryLookup &CurEntry = SearchList[i];

    if (CurEntry.isNormalDir()) {
      // If this isn't the first time we've seen this dir, remove it.
      if (SeenDirs.insert(CurEntry.getDir()))
        continue;
    } else if (CurEntry.isFramework()) {
      // If this isn't the first time we've seen this framework dir, remove it.
      if (SeenFrameworkDirs.insert(CurEntry.getFrameworkDir()))
        continue;
    } else {
      assert(CurEntry.isHeaderMap() && "Not a headermap or normal dir?");
      // If this isn't the first time we've seen this headermap, remove it.
      if (SeenHeaderMaps.insert(CurEntry.getHeaderMap()))
        continue;
    }

    // If we have a normal #include dir/framework/headermap that is shadowed
    // later in the chain by a system include location, we actually want to
    // ignore the user's request and drop the user dir... keeping the system
    // dir.  This is weird, but required to emulate GCC's search path correctly.
    //
    // Since dupes of system dirs are rare, just rescan to find the original
    // that we're nuking instead of using a DenseMap.
    if (CurEntry.getDirCharacteristic() != SrcMgr::C_User) {
      // Find the dir that this is the same of.
      unsigned FirstDir;
      for (FirstDir = 0; ; ++FirstDir) {
        assert(FirstDir != i && "Didn't find dupe?");

        const DirectoryLookup &SearchEntry = SearchList[FirstDir];

        // If these are different lookup types, then they can't be the dupe.
        if (SearchEntry.getLookupType() != CurEntry.getLookupType())
          continue;

        bool isSame;
        if (CurEntry.isNormalDir())
          isSame = SearchEntry.getDir() == CurEntry.getDir();
        else if (CurEntry.isFramework())
          isSame = SearchEntry.getFrameworkDir() == CurEntry.getFrameworkDir();
        else {
          assert(CurEntry.isHeaderMap() && "Not a headermap or normal dir?");
          isSame = SearchEntry.getHeaderMap() == CurEntry.getHeaderMap();
        }

        if (isSame)
          break;
      }

      // If the first dir in the search path is a non-system dir, zap it
      // instead of the system one.
      if (SearchList[FirstDir].getDirCharacteristic() == SrcMgr::C_User)
        DirToRemove = FirstDir;
    }

    if (Verbose) {
      fprintf(stderr, "ignoring duplicate directory \"%s\"\n",
              CurEntry.getName());
      if (DirToRemove != i)
        fprintf(stderr, "  as it is a non-system directory that duplicates"
                " a system directory\n");
    }

    // This is reached if the current entry is a duplicate.  Remove the
    // DirToRemove (usually the current dir).
    SearchList.erase(SearchList.begin()+DirToRemove);
    --i;
  }
}

void InitHeaderSearch::Realize() {
  // Concatenate ANGLE+SYSTEM+AFTER chains together into SearchList.
  std::vector<DirectoryLookup> SearchList;
  SearchList = IncludeGroup[Angled];
  SearchList.insert(SearchList.end(), IncludeGroup[System].begin(),
                    IncludeGroup[System].end());
  SearchList.insert(SearchList.end(), IncludeGroup[After].begin(),
                    IncludeGroup[After].end());
  RemoveDuplicates(SearchList, Verbose);
  RemoveDuplicates(IncludeGroup[Quoted], Verbose);

  // Prepend QUOTED list on the search list.
  SearchList.insert(SearchList.begin(), IncludeGroup[Quoted].begin(),
                    IncludeGroup[Quoted].end());

  bool DontSearchCurDir = false;  // TODO: set to true if -I- is set?
  Headers.SetSearchPaths(SearchList, IncludeGroup[Quoted].size(),
                         DontSearchCurDir);

  // If verbose, print the list of directories that will be searched.
  if (Verbose) {
    fprintf(stderr, "#include \"...\" search starts here:\n");
    unsigned QuotedIdx = IncludeGroup[Quoted].size();
    for (unsigned i = 0, e = SearchList.size(); i != e; ++i) {
      if (i == QuotedIdx)
        fprintf(stderr, "#include <...> search starts here:\n");
      const char *Name = SearchList[i].getName();
      const char *Suffix;
      if (SearchList[i].isNormalDir())
        Suffix = "";
      else if (SearchList[i].isFramework())
        Suffix = " (framework directory)";
      else {
        assert(SearchList[i].isHeaderMap() && "Unknown DirectoryLookup");
        Suffix = " (headermap)";
      }
      fprintf(stderr, " %s%s\n", Name, Suffix);
    }
    fprintf(stderr, "End of search list.\n");
  }
}

<|endoftext|>


<commit_before>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// version: $Id$
// author:  Vassil Vassilev <vasil.georgiev.vasilev@cern.ch>
//------------------------------------------------------------------------------

#include "DeclCollector.h"

#include "cling/Interpreter/Transaction.h"

#include "clang/AST/Decl.h"
#include "clang/AST/DeclGroup.h"

using namespace clang;

namespace cling {

  // pin the vtable here.
  DeclCollector::~DeclCollector() {
  }

  bool DeclCollector::HandleTopLevelDecl(DeclGroupRef DGR) {
    m_CurTransaction->appendUnique(DGR);
    return true;
  }

  void DeclCollector::HandleInterestingDecl(DeclGroupRef DGR) {
    assert("Not implemented yet!");
  }

  // Does more than we want:
  // if there is class A {enum E {kEnum = 1};};
  // we get two different tag decls one for A and one for E. This is not that
  // bad because esentially it has no effect on codegen but it differs from what
  // one'd expect. For now rely on the HandleTopLevelDecl to provide all the
  // declarations in the transaction.
  void DeclCollector::HandleTagDeclDefinition(TagDecl* TD) {
    // Intentional no-op.
  }

  void DeclCollector::HandleVTable(CXXRecordDecl* RD,
                                     bool DefinitionRequired) {
    assert("Not implemented yet!");
  }

  void DeclCollector::CompleteTentativeDefinition(VarDecl* VD) {
    assert("Not implemented yet!");
  }

  void DeclCollector::HandleTranslationUnit(ASTContext& Ctx) {
    assert("Not implemented yet!");
  }
} // namespace cling
<commit_msg>Assert actually on use of one of those routines in Sema.<commit_after>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// version: $Id$
// author:  Vassil Vassilev <vasil.georgiev.vasilev@cern.ch>
//------------------------------------------------------------------------------

#include "DeclCollector.h"

#include "cling/Interpreter/Transaction.h"

#include "clang/AST/Decl.h"
#include "clang/AST/DeclGroup.h"

using namespace clang;

namespace cling {

  // pin the vtable here.
  DeclCollector::~DeclCollector() {
  }

  bool DeclCollector::HandleTopLevelDecl(DeclGroupRef DGR) {
    m_CurTransaction->appendUnique(DGR);
    return true;
  }

  void DeclCollector::HandleInterestingDecl(DeclGroupRef DGR) {
    assert("Not implemented yet!");
  }

  // Does more than we want:
  // if there is class A {enum E {kEnum = 1};};
  // we get two different tag decls one for A and one for E. This is not that
  // bad because esentially it has no effect on codegen but it differs from what
  // one'd expect. For now rely on the HandleTopLevelDecl to provide all the
  // declarations in the transaction.
  void DeclCollector::HandleTagDeclDefinition(TagDecl* TD) {
    // Intentional no-op.
  }

  void DeclCollector::HandleVTable(CXXRecordDecl* RD, bool DefinitionRequired) {
    assert(0 && "Not implemented yet!");
  }

  void DeclCollector::CompleteTentativeDefinition(VarDecl* VD) {
    assert(0 && "Not implemented yet!");
  }

  void DeclCollector::HandleTranslationUnit(ASTContext& Ctx) {
  }
} // namespace cling
<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2006 Artem Pavlenko
 *
 * 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
 *
 *****************************************************************************/

//$Id: pool.hpp 39 2005-04-10 20:39:53Z pavlenko $

#ifndef POOL_HPP
#define POOL_HPP

// stl
#include <iostream>
#include <map>
#include <deque>
#include <ctime>
// boost
#include <boost/shared_ptr.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/utility.hpp>
// mapnik
#include <mapnik/utils.hpp>

namespace mapnik
{
    template <typename T, typename PoolT>
    class PoolGuard
    {
    private:
        const T& obj_;
        PoolT& pool_;
    public:
        explicit PoolGuard(const T& ptr,PoolT& pool)
            : obj_(ptr),
              pool_(pool) {}

        ~PoolGuard()
        {
            pool_->returnObject(obj_);
        }

    private:
        PoolGuard();
        PoolGuard(const PoolGuard&);
        PoolGuard& operator=(const PoolGuard&);
    };

    template <typename T,template <typename> class Creator>
    class Pool : private boost::noncopyable
    {
        typedef boost::shared_ptr<T> HolderType;
        typedef std::deque<HolderType> ContType;

        Creator<T> creator_;
        const unsigned initialSize_;
        const unsigned maxSize_;
        ContType usedPool_;
        ContType unusedPool_;
        boost::mutex mutex_;
    public:

        Pool(const Creator<T>& creator,unsigned initialSize=1, unsigned maxSize=10)
            :creator_(creator),
             initialSize_(initialSize),
             maxSize_(maxSize)
        {
            for (unsigned i=0; i < initialSize_; ++i)
            {
                unusedPool_.push_back(HolderType(creator_()));
            }
        }

        HolderType borrowObject()
        {
            mutex::scoped_lock lock(mutex_);
            typename ContType::iterator itr=unusedPool_.begin();
            if (itr!=unusedPool_.end())
            {
#ifdef MAPNIK_DEBUG
                std::clog<<"borrow "<<(*itr).get()<<"\n";
#endif
                usedPool_.push_back(*itr);
                itr=unusedPool_.erase(itr);
                return usedPool_[usedPool_.size()-1];
            }
            else if (unusedPool_.size() < maxSize_)
            {
                HolderType conn(creator_());
                usedPool_.push_back(conn);
#ifdef MAPNIK_DEBUG
                std::clog << "create << " << conn.get() << "\n";
#endif
                return conn;
            }

            return HolderType();
        }

        void returnObject(HolderType obj)
        {
            mutex::scoped_lock lock(mutex_);
            typename ContType::iterator itr=usedPool_.begin();
            while (itr != usedPool_.end())
            {
                if (obj.get()==(*itr).get())
                {
#ifdef MAPNIK_DEBUG
                    std::clog<<"return "<<(*itr).get()<<"\n";
#endif
                    unusedPool_.push_back(*itr);
                    usedPool_.erase(itr);
                    return;
                }
                ++itr;
            }
        }
    };
}
#endif //POOL_HPP
<commit_msg>don't keep bad connections around<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2006 Artem Pavlenko
 *
 * 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
 *
 *****************************************************************************/

//$Id: pool.hpp 39 2005-04-10 20:39:53Z pavlenko $

#ifndef POOL_HPP
#define POOL_HPP

// stl
#include <iostream>
#include <map>
#include <deque>
#include <ctime>
// boost
#include <boost/shared_ptr.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/utility.hpp>
// mapnik
#include <mapnik/utils.hpp>

namespace mapnik
{
    template <typename T, typename PoolT>
    class PoolGuard
    {
    private:
        const T& obj_;
        PoolT& pool_;
    public:
        explicit PoolGuard(const T& ptr,PoolT& pool)
            : obj_(ptr),
              pool_(pool) {}

        ~PoolGuard()
        {
            pool_->returnObject(obj_);
        }

    private:
        PoolGuard();
        PoolGuard(const PoolGuard&);
        PoolGuard& operator=(const PoolGuard&);
    };

    template <typename T,template <typename> class Creator>
    class Pool : private boost::noncopyable
    {
        typedef boost::shared_ptr<T> HolderType;
        typedef std::deque<HolderType> ContType;

        Creator<T> creator_;
        const unsigned initialSize_;
        const unsigned maxSize_;
        ContType usedPool_;
        ContType unusedPool_;
        boost::mutex mutex_;
    public:

        Pool(const Creator<T>& creator,unsigned initialSize=1, unsigned maxSize=10)
            :creator_(creator),
             initialSize_(initialSize),
             maxSize_(maxSize)
        {
            for (unsigned i=0; i < initialSize_; ++i)
            {
                HolderType conn(creator_());
                if (conn->isOK())
                    unusedPool_.push_back(conn);
            }
        }

        HolderType borrowObject()
        {
            mutex::scoped_lock lock(mutex_);
            typename ContType::iterator itr=unusedPool_.begin();
            if (itr!=unusedPool_.end())
            {
#ifdef MAPNIK_DEBUG
                std::clog<<"borrow "<<(*itr).get()<<"\n";
#endif
                usedPool_.push_back(*itr);
                itr=unusedPool_.erase(itr);
                return usedPool_[usedPool_.size()-1];
            }
            else if (unusedPool_.size() < maxSize_)
            {
                HolderType conn(creator_());
                if (conn->isOK())
                {
                    usedPool_.push_back(conn);
#ifdef MAPNIK_DEBUG
                std::clog << "create << " << conn.get() << "\n";
#endif
                return conn;
                }
            }
            return HolderType();
        }

        void returnObject(HolderType obj)
        {
            mutex::scoped_lock lock(mutex_);
            typename ContType::iterator itr=usedPool_.begin();
            while (itr != usedPool_.end())
            {
                if (obj.get()==(*itr).get())
                {
#ifdef MAPNIK_DEBUG
                    std::clog<<"return "<<(*itr).get()<<"\n";
#endif
                    unusedPool_.push_back(*itr);
                    usedPool_.erase(itr);
                    return;
                }
                ++itr;
            }
        }
    };
}
#endif //POOL_HPP
<|endoftext|>


<commit_before>//
// Copyright (c) 2013-2014 Christoph Malek
// See LICENSE for more information.
//

#ifndef MLK_LOG_LOG_INL
#define MLK_LOG_LOG_INL

#include "log_impl.h"

#include <mlk/filesystem/filesystem.h>
#include <mlk/signals_slots/signals_slots.h>

namespace mlk
{
	namespace logger
	{
		inline log_base<mlk::logger::log_level::normal>::log_base(bool save_history, bool write_on_exit, bool override_old_log, const std::string& save_path) :
			m_save_history{save_history},
			m_write_on_exit{write_on_exit},
			m_save_path{save_path},
			m_mode{override_old_log ? std::ios::out | std::ios::trunc : std::ios::out | std::ios::app}
		{ }

		inline log_base<mlk::logger::log_level::normal>::~log_base()
		{
			console::reset_color();

			if(m_write_on_exit && (!m_history.str().empty()))
			{
				if(!m_save_path.empty())
				{
					fs::fs_handle<fs::fs_type::file> file{m_save_path};
					file.open_io(m_mode);
					file.write(m_history.str());
				}
			}

			std::cout << std::endl;
		}

		inline void log_base<mlk::logger::log_level::normal>::entry_added(const std::string& last_entry)
		{emit_signal(m_entry_added, last_entry);}
	}
}

#endif // MLK_LOG_LOG_INL
<commit_msg>added flush on new entry<commit_after>//
// Copyright (c) 2013-2014 Christoph Malek
// See LICENSE for more information.
//

#ifndef MLK_LOG_LOG_INL
#define MLK_LOG_LOG_INL

#include "log_impl.h"

#include <mlk/filesystem/filesystem.h>
#include <mlk/signals_slots/signals_slots.h>

namespace mlk
{
	namespace logger
	{
		inline log_base<mlk::logger::log_level::normal>::log_base(bool save_history, bool write_on_exit, bool override_old_log, const std::string& save_path) :
			m_save_history{save_history},
			m_write_on_exit{write_on_exit},
			m_save_path{save_path},
			m_mode{override_old_log ? std::ios::out | std::ios::trunc : std::ios::out | std::ios::app}
		{ }

		inline log_base<mlk::logger::log_level::normal>::~log_base()
		{
			console::reset_color();

			if(m_write_on_exit && (!m_history.str().empty()))
			{
				if(!m_save_path.empty())
				{
					fs::fs_handle<fs::fs_type::file> file{m_save_path};
					file.open_io(m_mode);
					file.write(m_history.str());
				}
			}

			std::cout << std::endl;
		}

		inline void log_base<mlk::logger::log_level::normal>::entry_added(const std::string& last_entry)
		{
			emit_signal(m_entry_added, last_entry);
			std::cout().flush();
		}
	}
}

#endif // MLK_LOG_LOG_INL
<|endoftext|>


<commit_before>/* BEGIN_COMMON_COPYRIGHT_HEADER
 * (c)LGPL2+
 *
 * LXDE-Qt - a lightweight, Qt based, desktop toolset
 * http://razor-qt.org
 *
 * Copyright: 2010-2012 Razor team
 * Authors:
 *   Petr Vanek <petr@scribus.info>
 *   Kuzma Shapran <kuzma.shapran@gmail.com>
 *
 * This program or 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 Street, Fifth Floor,
 * Boston, MA 02110-1301 USA
 *
 * END_COMMON_COPYRIGHT_HEADER */

#include "lxqtquicklaunch.h"
#include "quicklaunchbutton.h"
#include <LXQt/GridLayout>
#include "quicklaunchaction.h"
#include "../panel/ilxqtpanelplugin.h"

#include <XdgDesktopFile>
#include <XdgIcon>

#include <QtDebug>
#include <QSettings>
#include <QUrl>
#include <QFileInfo>
#include <QDragEnterEvent>
#include <QToolButton>
#include <QMessageBox>
#include <QDesktopServices>
#include <QFileIconProvider>
#include <QSettings>
#include <QLabel>
#include "desktopfile.h"

LxQtQuickLaunch::LxQtQuickLaunch(ILxQtPanelPlugin *plugin, QWidget* parent) :
    QFrame(parent),
    mPlugin(plugin),
    mPlaceHolder(0)
{
    setAcceptDrops(true);

    mLayout = new LxQt::GridLayout(this);
    setLayout(mLayout);

    QSettings *settings = mPlugin->settings();
    int count = settings->beginReadArray("apps");

    QString desktop;
    QString file;
    QString execname;
    QString exec;
    QString icon;
    for (int i = 0; i < count; ++i)
    {
        settings->setArrayIndex(i);
        desktop = settings->value("desktop", "").toString();
        file = settings->value("file", "").toString();
        if (! desktop.isEmpty())
        {
            XdgDesktopFile xdg;
            if(!loadDesktopFile(xdg, desktop))
            {
                qDebug() << "XdgDesktopFile" << desktop << "is not valid";
                continue;
            }
            if (!xdg.isSuitable())
            {
                qDebug() << "XdgDesktopFile" << desktop << "is not applicable";
                continue;
            }

            addButton(new QuickLaunchAction(&xdg, this));
        }
        else if (! file.isEmpty())
        {
            addButton(new QuickLaunchAction(file, this));
        }
        else
        {
            execname = settings->value("name", "").toString();
            exec = settings->value("exec", "").toString();
            icon = settings->value("icon", "").toString();
            if (icon.isNull())
            {
                qDebug() << "Icon" << icon << "is not valid (isNull). Skipped.";
                continue;
            }
            addButton(new QuickLaunchAction(execname, exec, icon, this));
        }
    } // for

    settings->endArray();

    if (mLayout->isEmpty())
        showPlaceHolder();

    realign();
}

LxQtQuickLaunch::~LxQtQuickLaunch()
{
}

int LxQtQuickLaunch::indexOfButton(QuickLaunchButton* button) const
{
    return mLayout->indexOf(button);
}

int LxQtQuickLaunch::countOfButtons() const
{
    return mLayout->count();
}

void LxQtQuickLaunch::realign()
{
    mLayout->setEnabled(false);
    ILxQtPanel *panel = mPlugin->panel();

    if (mPlaceHolder)
    {
        mLayout->setColumnCount(1);
        mLayout->setRowCount(1);
    }
    else
    {
        if (panel->isHorizontal())
        {
            mLayout->setRowCount(panel->lineCount());
            mLayout->setColumnCount(0);
        }
        else
        {
            mLayout->setColumnCount(panel->lineCount());
            mLayout->setRowCount(0);
        }
    }
    mLayout->setEnabled(true);
}

void LxQtQuickLaunch::addButton(QuickLaunchAction* action)
{
    mLayout->setEnabled(false);
    QuickLaunchButton* btn = new QuickLaunchButton(action, this);
    mLayout->addWidget(btn);

    connect(btn, SIGNAL(switchButtons(QuickLaunchButton*,QuickLaunchButton*)), this, SLOT(switchButtons(QuickLaunchButton*,QuickLaunchButton*)));
    connect(btn, SIGNAL(buttonDeleted()), this, SLOT(buttonDeleted()));
    connect(btn, SIGNAL(movedLeft()), this, SLOT(buttonMoveLeft()));
    connect(btn, SIGNAL(movedRight()), this, SLOT(buttonMoveRight()));

    mLayout->removeWidget(mPlaceHolder);
    delete mPlaceHolder;
    mPlaceHolder = 0;
    mLayout->setEnabled(true);
    realign();
}

void LxQtQuickLaunch::dragEnterEvent(QDragEnterEvent *e)
{
    // Getting URL from mainmenu...
    if (e->mimeData()->hasUrls())
    {
        e->acceptProposedAction();
        return;
    }

    if (e->source() && e->source()->parent() == this)
    {
        e->acceptProposedAction();
    }
}

void LxQtQuickLaunch::dropEvent(QDropEvent *e)
{
    const QMimeData *mime = e->mimeData();
    // duplicates storage: [quicklaunch] issue dragging from qtfm, #252
    QList<QUrl> duplicates;
    // urls from mainmenu
    foreach (QUrl url, mime->urls())
    {
        if (duplicates.contains(url))
            continue;
        else
            duplicates << url;

        QString fileName(url.url());
        XdgDesktopFile xdg;
        QFileInfo fi(fileName);

        if (loadDesktopFile(xdg, fileName))
        {
            if (xdg.isSuitable())
                addButton(new QuickLaunchAction(&xdg, this));
        }
        else if (fi.exists() && fi.isExecutable() && !fi.isDir())
        {
            addButton(new QuickLaunchAction(fileName, fileName, "", this));
        }
        else if (fi.exists())
        {
            addButton(new QuickLaunchAction(fileName, this));
        }
        else
        {
            qWarning() << "XdgDesktopFile" << fileName << "is not valid";
            QMessageBox::information(this, tr("Drop Error"),
                              tr("File/URL '%1' cannot be embedded into QuickLaunch for now").arg(fileName)
                            );
        }
    }
    saveSettings();
}

void LxQtQuickLaunch::switchButtons(QuickLaunchButton *button1, QuickLaunchButton *button2)
{
    if (button1 == button2)
        return;

    int n1 = mLayout->indexOf(button1);
    int n2 = mLayout->indexOf(button2);

    int l = qMin(n1, n2);
    int m = qMax(n1, n2);

    mLayout->moveItem(l, m);
    mLayout->moveItem(m-1, l);
    saveSettings();
}

void LxQtQuickLaunch::buttonDeleted()
{
    QuickLaunchButton *btn = qobject_cast<QuickLaunchButton*>(sender());
    if (!btn)
        return;

    mLayout->removeWidget(btn);
    btn->deleteLater();
    saveSettings();

    if (mLayout->isEmpty())
        showPlaceHolder();

    realign();
}

void LxQtQuickLaunch::buttonMoveLeft()
{
    QuickLaunchButton *btn = qobject_cast<QuickLaunchButton*>(sender());
    if (!btn)
        return;

    int index = indexOfButton(btn);
    if (index > 0)
    {
        mLayout->moveItem(index, index - 1);
        saveSettings();
    }
}

void LxQtQuickLaunch::buttonMoveRight()
{
    QuickLaunchButton *btn1 = qobject_cast<QuickLaunchButton*>(sender());
    if (!btn1)
        return;

    int index = indexOfButton(btn1);
    if (index < countOfButtons() - 1)
    {
        mLayout->moveItem(index, index + 1);
        saveSettings();
    }
}

void LxQtQuickLaunch::saveSettings()
{
    QSettings *settings = mPlugin->settings();
    settings->remove("apps");
    settings->beginWriteArray("apps");
    int i = 0;

    for(int j=0; j<mLayout->count(); ++j)
    {
        QuickLaunchButton *b = qobject_cast<QuickLaunchButton*>(mLayout->itemAt(j)->widget());
        if(!b)
            continue;

        settings->setArrayIndex(i);

        QHashIterator<QString,QString> it(b->settingsMap());
        while (it.hasNext())
        {
            it.next();
            settings->setValue(it.key(), it.value());
        }

        ++i;
    }

    settings->endArray();
}

void LxQtQuickLaunch::showPlaceHolder()
{
    if (!mPlaceHolder)
    {
        mPlaceHolder = new QLabel(this);
        mPlaceHolder->setAlignment(Qt::AlignCenter);
        mPlaceHolder->setObjectName("QuickLaunchPlaceHolder");
        mPlaceHolder->setText(tr("Drop application\nicons here"));
    }

    mLayout->addWidget(mPlaceHolder);
}
<commit_msg>Fixes lxde/lxde-qt#325. Drop .desktop files on quicklaunch<commit_after>/* BEGIN_COMMON_COPYRIGHT_HEADER
 * (c)LGPL2+
 *
 * LXDE-Qt - a lightweight, Qt based, desktop toolset
 * http://razor-qt.org
 *
 * Copyright: 2010-2012 Razor team
 * Authors:
 *   Petr Vanek <petr@scribus.info>
 *   Kuzma Shapran <kuzma.shapran@gmail.com>
 *
 * This program or 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 Street, Fifth Floor,
 * Boston, MA 02110-1301 USA
 *
 * END_COMMON_COPYRIGHT_HEADER */

#include "lxqtquicklaunch.h"
#include "quicklaunchbutton.h"
#include <LXQt/GridLayout>
#include "quicklaunchaction.h"
#include "../panel/ilxqtpanelplugin.h"

#include <XdgDesktopFile>
#include <XdgIcon>

#include <QtDebug>
#include <QSettings>
#include <QUrl>
#include <QFileInfo>
#include <QDragEnterEvent>
#include <QToolButton>
#include <QMessageBox>
#include <QDesktopServices>
#include <QFileIconProvider>
#include <QSettings>
#include <QLabel>
#include "desktopfile.h"

LxQtQuickLaunch::LxQtQuickLaunch(ILxQtPanelPlugin *plugin, QWidget* parent) :
    QFrame(parent),
    mPlugin(plugin),
    mPlaceHolder(0)
{
    setAcceptDrops(true);

    mLayout = new LxQt::GridLayout(this);
    setLayout(mLayout);

    QSettings *settings = mPlugin->settings();
    int count = settings->beginReadArray("apps");

    QString desktop;
    QString file;
    QString execname;
    QString exec;
    QString icon;
    for (int i = 0; i < count; ++i)
    {
        settings->setArrayIndex(i);
        desktop = settings->value("desktop", "").toString();
        file = settings->value("file", "").toString();
        if (! desktop.isEmpty())
        {
            XdgDesktopFile xdg;
            if(!loadDesktopFile(xdg, desktop))
            {
                qDebug() << "XdgDesktopFile" << desktop << "is not valid";
                continue;
            }
            if (!xdg.isSuitable())
            {
                qDebug() << "XdgDesktopFile" << desktop << "is not applicable";
                continue;
            }

            addButton(new QuickLaunchAction(&xdg, this));
        }
        else if (! file.isEmpty())
        {
            addButton(new QuickLaunchAction(file, this));
        }
        else
        {
            execname = settings->value("name", "").toString();
            exec = settings->value("exec", "").toString();
            icon = settings->value("icon", "").toString();
            if (icon.isNull())
            {
                qDebug() << "Icon" << icon << "is not valid (isNull). Skipped.";
                continue;
            }
            addButton(new QuickLaunchAction(execname, exec, icon, this));
        }
    } // for

    settings->endArray();

    if (mLayout->isEmpty())
        showPlaceHolder();

    realign();
}

LxQtQuickLaunch::~LxQtQuickLaunch()
{
}

int LxQtQuickLaunch::indexOfButton(QuickLaunchButton* button) const
{
    return mLayout->indexOf(button);
}

int LxQtQuickLaunch::countOfButtons() const
{
    return mLayout->count();
}

void LxQtQuickLaunch::realign()
{
    mLayout->setEnabled(false);
    ILxQtPanel *panel = mPlugin->panel();

    if (mPlaceHolder)
    {
        mLayout->setColumnCount(1);
        mLayout->setRowCount(1);
    }
    else
    {
        if (panel->isHorizontal())
        {
            mLayout->setRowCount(panel->lineCount());
            mLayout->setColumnCount(0);
        }
        else
        {
            mLayout->setColumnCount(panel->lineCount());
            mLayout->setRowCount(0);
        }
    }
    mLayout->setEnabled(true);
}

void LxQtQuickLaunch::addButton(QuickLaunchAction* action)
{
    mLayout->setEnabled(false);
    QuickLaunchButton* btn = new QuickLaunchButton(action, this);
    mLayout->addWidget(btn);

    connect(btn, SIGNAL(switchButtons(QuickLaunchButton*,QuickLaunchButton*)), this, SLOT(switchButtons(QuickLaunchButton*,QuickLaunchButton*)));
    connect(btn, SIGNAL(buttonDeleted()), this, SLOT(buttonDeleted()));
    connect(btn, SIGNAL(movedLeft()), this, SLOT(buttonMoveLeft()));
    connect(btn, SIGNAL(movedRight()), this, SLOT(buttonMoveRight()));

    mLayout->removeWidget(mPlaceHolder);
    delete mPlaceHolder;
    mPlaceHolder = 0;
    mLayout->setEnabled(true);
    realign();
}

void LxQtQuickLaunch::dragEnterEvent(QDragEnterEvent *e)
{
    // Getting URL from mainmenu...
    if (e->mimeData()->hasUrls())
    {
        e->acceptProposedAction();
        return;
    }

    if (e->source() && e->source()->parent() == this)
    {
        e->acceptProposedAction();
    }
}

void LxQtQuickLaunch::dropEvent(QDropEvent *e)
{
    const QMimeData *mime = e->mimeData();

    foreach (QUrl url, mime->urls().toSet())
    {
        QString fileName(url.isLocalFile() ? url.toLocalFile() : url.url());
        QFileInfo fi(fileName);
        XdgDesktopFile xdg;

        if (loadDesktopFile(xdg, fileName))
        {
            if (xdg.isSuitable())
                addButton(new QuickLaunchAction(&xdg, this));
        }
        else if (fi.exists() && fi.isExecutable() && !fi.isDir())
        {
            addButton(new QuickLaunchAction(fileName, fileName, "", this));
        }
        else if (fi.exists())
        {
            addButton(new QuickLaunchAction(fileName, this));
        }
        else
        {
            qWarning() << "XdgDesktopFile" << fileName << "is not valid";
            QMessageBox::information(this, tr("Drop Error"),
                              tr("File/URL '%1' cannot be embedded into QuickLaunch for now").arg(fileName)
                            );
        }
    }
    saveSettings();
}

void LxQtQuickLaunch::switchButtons(QuickLaunchButton *button1, QuickLaunchButton *button2)
{
    if (button1 == button2)
        return;

    int n1 = mLayout->indexOf(button1);
    int n2 = mLayout->indexOf(button2);

    int l = qMin(n1, n2);
    int m = qMax(n1, n2);

    mLayout->moveItem(l, m);
    mLayout->moveItem(m-1, l);
    saveSettings();
}

void LxQtQuickLaunch::buttonDeleted()
{
    QuickLaunchButton *btn = qobject_cast<QuickLaunchButton*>(sender());
    if (!btn)
        return;

    mLayout->removeWidget(btn);
    btn->deleteLater();
    saveSettings();

    if (mLayout->isEmpty())
        showPlaceHolder();

    realign();
}

void LxQtQuickLaunch::buttonMoveLeft()
{
    QuickLaunchButton *btn = qobject_cast<QuickLaunchButton*>(sender());
    if (!btn)
        return;

    int index = indexOfButton(btn);
    if (index > 0)
    {
        mLayout->moveItem(index, index - 1);
        saveSettings();
    }
}

void LxQtQuickLaunch::buttonMoveRight()
{
    QuickLaunchButton *btn1 = qobject_cast<QuickLaunchButton*>(sender());
    if (!btn1)
        return;

    int index = indexOfButton(btn1);
    if (index < countOfButtons() - 1)
    {
        mLayout->moveItem(index, index + 1);
        saveSettings();
    }
}

void LxQtQuickLaunch::saveSettings()
{
    QSettings *settings = mPlugin->settings();
    settings->remove("apps");
    settings->beginWriteArray("apps");
    int i = 0;

    for(int j=0; j<mLayout->count(); ++j)
    {
        QuickLaunchButton *b = qobject_cast<QuickLaunchButton*>(mLayout->itemAt(j)->widget());
        if(!b)
            continue;

        settings->setArrayIndex(i);

        QHashIterator<QString,QString> it(b->settingsMap());
        while (it.hasNext())
        {
            it.next();
            settings->setValue(it.key(), it.value());
        }

        ++i;
    }

    settings->endArray();
}

void LxQtQuickLaunch::showPlaceHolder()
{
    if (!mPlaceHolder)
    {
        mPlaceHolder = new QLabel(this);
        mPlaceHolder->setAlignment(Qt::AlignCenter);
        mPlaceHolder->setObjectName("QuickLaunchPlaceHolder");
        mPlaceHolder->setText(tr("Drop application\nicons here"));
    }

    mLayout->addWidget(mPlaceHolder);
}
<|endoftext|>


<commit_before>#include "wintoastlib.h"
using namespace WinToastLib;

// Function load a function from library
template <typename Function>
HRESULT loadFunctionFromLibrary(HINSTANCE library, LPCSTR name, Function &func) {
    if (!library) return false;

    func = reinterpret_cast<Function>(GetProcAddress(library, name));
    return (func != nullptr) ? S_OK : E_FAIL;
}

WinToast* WinToast::_instance = nullptr;
WinToast* WinToast::instance() {
    if (_instance == nullptr) {
        _instance = new WinToast();
    }
    return _instance;
}

WinToast::WinToast() : _isInitialized(false)
{
    DllImporter::initialize();
}

void WinToast::setAppName(_In_ const std::wstring& appName) {
    _appName = appName;
}

std::wstring WinToast::appName() const {
    return _appName;
}

std::wstring WinToast::appUserModelId() const {
    return _aumi;
}
void WinToast::setAppUserModelId(_In_ const std::wstring& aumi) {
    _aumi = aumi;
}

bool WinToast::isCompatible() {
        return !((DllImporter::SetCurrentProcessExplicitAppUserModelID == nullptr)
            || (DllImporter::PropVariantToString == nullptr)
            || (DllImporter::RoGetActivationFactory == nullptr)
            || (DllImporter::WindowsCreateStringReference == nullptr)
            || (DllImporter::WindowsDeleteString == nullptr));
}

bool WinToast::initialize() {
    if (_aumi.empty() || _appName.empty()) {
        std::wcout << L"Error: App User Model Id or Appname is empty!" << std::endl;
        _isInitialized = false;
        return false;
    }

    if (!isCompatible()) {
        std::wcout << L"Your OS is not compatible with this library! =(" << std::endl;
        _isInitialized = false;
        return _isInitialized;
    }

    // Validate the last Shell Link - Shoul have the same AUMI.
    HRESULT hr = validateShellLink();
    if (FAILED(hr)) {
        hr = createShellLink();
    }

    if (SUCCEEDED(hr)) {
        hr = DllImporter::Wrap_GetActivationFactory(WinToastStringWrapper(RuntimeClass_Windows_UI_Notifications_ToastNotificationManager).Get(), &_notificationManager);
        if (SUCCEEDED(hr)) {
            hr = notificationManager()->CreateToastNotifierWithId(WinToastStringWrapper(_aumi).Get(), &_notifier);
            if (SUCCEEDED(hr)) {
                hr = DllImporter::Wrap_GetActivationFactory(WinToastStringWrapper(RuntimeClass_Windows_UI_Notifications_ToastNotification).Get(), &_notificationFactory);
            }
        }
    }

    _isInitialized = SUCCEEDED(hr);
    return _isInitialized;
}

HRESULT	WinToast::validateShellLink() {

    WCHAR	_path[MAX_PATH];
    Util::defaultShellLinkPath(_appName, _path);
    // Check if the file exist
    DWORD attr = GetFileAttributes(_path);
    if (attr >= 0xFFFFFFF) {
        std::wcout << "Error, shell link not found. Try to create a new one in: " << _path << std::endl;
        return E_FAIL;
    }

    // Let's load the file as shell link to validate.
    // - Create a shell link
    // - Create a persistant file
    // - Load the path as data for the persistant file
    // - Read the property AUMI and validate with the current
    // - Review if AUMI is equal.
    ComPtr<IShellLink> shellLink;
    HRESULT hr = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&shellLink));
    if (SUCCEEDED(hr)) {
        ComPtr<IPersistFile> persistFile;
        hr = shellLink.As(&persistFile);
        if (SUCCEEDED(hr)) {
            hr = persistFile->Load(_path, STGM_READWRITE);
            if (SUCCEEDED(hr)) {
                ComPtr<IPropertyStore> propertyStore;
                hr = shellLink.As(&propertyStore);
                if (SUCCEEDED(hr)) {
                    PROPVARIANT appIdPropVar;
                    hr = propertyStore->GetValue(PKEY_AppUserModel_ID, &appIdPropVar);
                    if (SUCCEEDED(hr)) {
                        WCHAR AUMI[MAX_PATH];
                        hr = DllImporter::PropVariantToString(appIdPropVar, AUMI, MAX_PATH);
                        if (SUCCEEDED(hr)) {
                            hr = (_aumi == AUMI) ? S_OK : E_FAIL;
                        }
                    }
                    PropVariantClear(&appIdPropVar);
                }
            }
        }
    }
    return hr;
}

HRESULT	WinToast::createShellLink() {
    WCHAR   exePath[MAX_PATH];
    WCHAR	slPath[MAX_PATH];
    Util::defaultShellLinkPath(_appName, slPath);
    Util::defaultExecutablePath(exePath);
    ComPtr<IShellLink> shellLink;
    HRESULT hr = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&shellLink));
    if (SUCCEEDED(hr)) {
        hr = shellLink->SetPath(exePath);
        if (SUCCEEDED(hr)) {
            hr = shellLink->SetArguments(L"");
            if (SUCCEEDED(hr)) {
                hr = shellLink->SetWorkingDirectory(exePath);
                if (SUCCEEDED(hr)) {
                    ComPtr<IPropertyStore> propertyStore;
                    hr = shellLink.As(&propertyStore);
                    if (SUCCEEDED(hr)) {
                        PROPVARIANT appIdPropVar;
                        hr = InitPropVariantFromString(_aumi.c_str(), &appIdPropVar);
                        if (SUCCEEDED(hr)) {
                            hr = propertyStore->SetValue(PKEY_AppUserModel_ID, appIdPropVar);
                            if (SUCCEEDED(hr)) {
                                hr = propertyStore->Commit();
                                if (SUCCEEDED(hr)) {
                                    ComPtr<IPersistFile> persistFile;
                                    hr = shellLink.As(&persistFile);
                                    if (SUCCEEDED(hr)) {
                                        hr = persistFile->Save(slPath, TRUE);
                                    }
                                }
                            }
                        }
                        PropVariantClear(&appIdPropVar);
                    }
                }
            }
        }
    }
    CoTaskMemFree(exePath);
    CoTaskMemFree(slPath);
    return hr;
}

bool WinToast::showToast(_In_ WinToastTemplate& toast)  {
    if (!isInitialized()) {
        std::wcout << "Error when launching the toast. WinToast is not initialized =(" << std::endl;
        return _isInitialized;
    }

    HRESULT hr = _notificationManager->GetTemplateContent(ToastTemplateType(toast.type()), &_xmlDocument);
    if (SUCCEEDED(hr)) {
        for (int i = 0; i < toast.textFieldsCount() && SUCCEEDED(hr); i++) {
            hr = setTextField(toast.textField(i), i);
        }
        if (SUCCEEDED(hr)) {
            hr = toast.hasImage() ? setImageField(toast.imagePath()) : hr;
            if (SUCCEEDED(hr)) {
                hr = _notificationFactory->CreateToastNotification(xmlDocument(), &_notification);
                if (SUCCEEDED(hr)) {
                    hr = Util::setEventHandlers(notification(), toast.handler());
                    if (SUCCEEDED(hr)) {
                        hr = _notifier->Show(notification());
                        if (SUCCEEDED(hr)) {
                        }
                    }
                }
            }
        }
    }

    return SUCCEEDED(hr);
}

HRESULT WinToast::setTextField(_In_ const std::wstring& text, int pos) {
    ComPtr<IXmlNodeList> nodeList;
    HRESULT hr = _xmlDocument->GetElementsByTagName(WinToastStringWrapper(L"text").Get(), &nodeList);
    if (SUCCEEDED(hr)) {
        ComPtr<IXmlNode> node;
        hr = nodeList->Item(pos, &node);
        if (SUCCEEDED(hr)) {
            hr = Util::setNodeStringValue(text, node.Get(), xmlDocument());
        }
    }
    return hr;
}

HRESULT WinToast::setImageField(_In_ const std::wstring& path)  {
    wchar_t imagePath[MAX_PATH] = L"file:///";
    HRESULT hr = StringCchCat(imagePath, MAX_PATH, path.c_str());
    if (SUCCEEDED(hr)) {
        ComPtr<IXmlNodeList> nodeList;
        HRESULT hr = _xmlDocument->GetElementsByTagName(WinToastStringWrapper(L"image").Get(), &nodeList);
        if (SUCCEEDED(hr)) {
            ComPtr<IXmlNode> node;
            hr = nodeList->Item(0, &node);
            if (SUCCEEDED(hr))  {
                ComPtr<IXmlNamedNodeMap> attributes;
                hr = node->get_Attributes(&attributes);
                if (SUCCEEDED(hr)) {
                    ComPtr<IXmlNode> editedNode;
                    hr = attributes->GetNamedItem(WinToastStringWrapper(L"src").Get(), &editedNode);
                    if (SUCCEEDED(hr)) {
                        Util::setNodeStringValue(imagePath, editedNode.Get(), xmlDocument());
                    }
                }
            }
        }
    }
    return hr;
}

WinToastTemplate::WinToastTemplate(const WinToastTemplateType& type) :
    _type(type)
{
    initComponentsFromType();
}

WinToastTemplate::~WinToastTemplate()
{
    _textFields.clear();
}

WinToastHandler *WinToastTemplate::handler() const
{
    return new WinToastHandler;
}

void WinToastTemplate::setTextField(const std::wstring& txt, int pos) {
    _textFields[pos] = txt;
}
void WinToastTemplate::setImagePath(const std::wstring& imgPath) {
    if (!_hasImage)
        return;
    _imagePath = imgPath;
}

void WinToastTemplate::initComponentsFromType() {
    _hasImage = _type < ToastTemplateType_ToastText01;
    _textFieldsCount = (_hasImage ? _type : _type - ToastTemplateType_ToastText01) + 1;
    _textFields = std::vector<std::wstring>(_textFieldsCount, L"");
}

WinToastHandler::WinToastHandler(_In_ HWND hToActivate, _In_ HWND hEdit) :
    _ref(1),
    _hToActivate(hToActivate),
    _hEdit(hEdit)
{
}

WinToastHandler::~WinToastHandler()
{
}

IFACEMETHODIMP WinToastHandler::QueryInterface(_In_ REFIID riid, _COM_Outptr_ void **ppv) {
    if (IsEqualIID(riid, IID_IUnknown))
        *ppv = static_cast<IUnknown*>(static_cast<ToastActivatedEventHandler*>(this));
    else if (IsEqualIID(riid, __uuidof(ToastActivatedEventHandler)))
        *ppv = static_cast<ToastActivatedEventHandler*>(this);
    else if (IsEqualIID(riid, __uuidof(ToastActivatedEventHandler)))
        *ppv = static_cast<ToastDismissedEventHandler*>(this);
    else if (IsEqualIID(riid, __uuidof(ToastFailedEventHandler)))
        *ppv = static_cast<ToastFailedEventHandler*>(this);
    else *ppv = nullptr;

    if (*ppv) {
        reinterpret_cast<IUnknown*>(*ppv)->AddRef();
        return S_OK;
    }

    return E_NOINTERFACE;
}

void WinToastHandler::toastActivated() const {
    std::wcout << L"The user clicked in this toast" << std::endl;

}

void WinToastHandler::toastFailed() const {
    std::wcout << L"Error showing current toast" << std::endl;
}

void WinToastHandler::toastDismissed(WinToastHandler::WinToastDismissalReason state) const {
    switch (state) {
    case UserCanceled:
        std::wcout << L"The user dismissed this toast" << std::endl;
        break;
    case ApplicationHidden:
        std::wcout <<  L"The application hid the toast using ToastNotifier.hide()" << std::endl;
        break;
    case TimedOut:
        std::wcout << L"The toast has timed out" << std::endl;
        break;
    default:
        std::wcout << L"Toast not activated" << std::endl;
        break;
    }
}

IFACEMETHODIMP_(ULONG) WinToastHandler::AddRef()
{
    return InterlockedIncrement(&_ref);
}

IFACEMETHODIMP_(ULONG) WinToastHandler::Release()
{
    ULONG l = InterlockedDecrement(&_ref);
    if (l == 0) {
        delete this;
    }
    return l;
}

IFACEMETHODIMP WinToastHandler::Invoke(_In_ IToastNotification *toast, _In_ IToastFailedEventArgs *e) {
    BOOL succeeded = SetForegroundWindow(_hToActivate);
    toastFailed();
    return succeeded ? S_OK : E_FAIL;
}

IFACEMETHODIMP WinToastHandler::Invoke(_In_ IToastNotification *toast, _In_ IInspectable *instpectable) {
    toastActivated();
    return S_OK;
}

IFACEMETHODIMP WinToastHandler::Invoke(_In_ IToastNotification *toast, _In_ IToastDismissedEventArgs *e)  {
    ToastDismissalReason tdr;
    HRESULT hr = e->get_Reason(&tdr);
    if (SUCCEEDED(hr))
    {
       toastDismissed(static_cast<WinToastDismissalReason>(tdr));
    }
    return hr;
}

HRESULT DllImporter::initialize() {
    HINSTANCE LibShell32 = LoadLibrary(L"SHELL32.DLL");
    HRESULT hr = loadFunctionFromLibrary(LibShell32, "SetCurrentProcessExplicitAppUserModelID", SetCurrentProcessExplicitAppUserModelID);
    if (SUCCEEDED(hr)) {
        HINSTANCE LibPropSys = LoadLibrary(L"PROPSYS.DLL");
        hr = loadFunctionFromLibrary(LibPropSys, "PropVariantToString", PropVariantToString);
        if (SUCCEEDED(hr)) {
            HINSTANCE LibComBase = LoadLibrary(L"COMBASE.DLL");
            return SUCCEEDED(loadFunctionFromLibrary(LibComBase, "RoGetActivationFactory", RoGetActivationFactory))
                    && SUCCEEDED(loadFunctionFromLibrary(LibComBase, "WindowsCreateStringReference", WindowsCreateStringReference))
                    && SUCCEEDED(loadFunctionFromLibrary(LibComBase, "WindowsDeleteString", WindowsDeleteString));
        }
    }
    return hr;
}
<commit_msg>Fixing posible warnings under compilation<commit_after>#include "wintoastlib.h"
using namespace WinToastLib;

// Function load a function from library
template <typename Function>
HRESULT loadFunctionFromLibrary(HINSTANCE library, LPCSTR name, Function &func) {
    if (!library) return false;

    func = reinterpret_cast<Function>(GetProcAddress(library, name));
    return (func != nullptr) ? S_OK : E_FAIL;
}

WinToast* WinToast::_instance = nullptr;
WinToast* WinToast::instance() {
    if (_instance == nullptr) {
        _instance = new WinToast();
    }
    return _instance;
}

WinToast::WinToast() : _isInitialized(false)
{
    DllImporter::initialize();
}

void WinToast::setAppName(_In_ const std::wstring& appName) {
    _appName = appName;
}

std::wstring WinToast::appName() const {
    return _appName;
}

std::wstring WinToast::appUserModelId() const {
    return _aumi;
}
void WinToast::setAppUserModelId(_In_ const std::wstring& aumi) {
    _aumi = aumi;
}

bool WinToast::isCompatible() {
        return !((DllImporter::SetCurrentProcessExplicitAppUserModelID == nullptr)
            || (DllImporter::PropVariantToString == nullptr)
            || (DllImporter::RoGetActivationFactory == nullptr)
            || (DllImporter::WindowsCreateStringReference == nullptr)
            || (DllImporter::WindowsDeleteString == nullptr));
}

bool WinToast::initialize() {
    if (_aumi.empty() || _appName.empty()) {
        std::wcout << L"Error: App User Model Id or Appname is empty!" << std::endl;
        _isInitialized = false;
        return false;
    }

    if (!isCompatible()) {
        std::wcout << L"Your OS is not compatible with this library! =(" << std::endl;
        _isInitialized = false;
        return _isInitialized;
    }

    // Validate the last Shell Link - Shoul have the same AUMI.
    HRESULT hr = validateShellLink();
    if (FAILED(hr)) {
        hr = createShellLink();
    }

    if (SUCCEEDED(hr)) {
        hr = DllImporter::Wrap_GetActivationFactory(WinToastStringWrapper(RuntimeClass_Windows_UI_Notifications_ToastNotificationManager).Get(), &_notificationManager);
        if (SUCCEEDED(hr)) {
            hr = notificationManager()->CreateToastNotifierWithId(WinToastStringWrapper(_aumi).Get(), &_notifier);
            if (SUCCEEDED(hr)) {
                hr = DllImporter::Wrap_GetActivationFactory(WinToastStringWrapper(RuntimeClass_Windows_UI_Notifications_ToastNotification).Get(), &_notificationFactory);
            }
        }
    }

    _isInitialized = SUCCEEDED(hr);
    return _isInitialized;
}

HRESULT	WinToast::validateShellLink() {

    WCHAR	_path[MAX_PATH];
    Util::defaultShellLinkPath(_appName, _path);
    // Check if the file exist
    DWORD attr = GetFileAttributes(_path);
    if (attr >= 0xFFFFFFF) {
        std::wcout << "Error, shell link not found. Try to create a new one in: " << _path << std::endl;
        return E_FAIL;
    }

    // Let's load the file as shell link to validate.
    // - Create a shell link
    // - Create a persistant file
    // - Load the path as data for the persistant file
    // - Read the property AUMI and validate with the current
    // - Review if AUMI is equal.
    ComPtr<IShellLink> shellLink;
    HRESULT hr = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&shellLink));
    if (SUCCEEDED(hr)) {
        ComPtr<IPersistFile> persistFile;
        hr = shellLink.As(&persistFile);
        if (SUCCEEDED(hr)) {
            hr = persistFile->Load(_path, STGM_READWRITE);
            if (SUCCEEDED(hr)) {
                ComPtr<IPropertyStore> propertyStore;
                hr = shellLink.As(&propertyStore);
                if (SUCCEEDED(hr)) {
                    PROPVARIANT appIdPropVar;
                    hr = propertyStore->GetValue(PKEY_AppUserModel_ID, &appIdPropVar);
                    if (SUCCEEDED(hr)) {
                        WCHAR AUMI[MAX_PATH];
                        hr = DllImporter::PropVariantToString(appIdPropVar, AUMI, MAX_PATH);
                        if (SUCCEEDED(hr)) {
                            hr = (_aumi == AUMI) ? S_OK : E_FAIL;
                        }
                    }
                    PropVariantClear(&appIdPropVar);
                }
            }
        }
    }
    return hr;
}

HRESULT	WinToast::createShellLink() {
    WCHAR   exePath[MAX_PATH];
    WCHAR	slPath[MAX_PATH];
    Util::defaultShellLinkPath(_appName, slPath);
    Util::defaultExecutablePath(exePath);
    ComPtr<IShellLink> shellLink;
    HRESULT hr = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&shellLink));
    if (SUCCEEDED(hr)) {
        hr = shellLink->SetPath(exePath);
        if (SUCCEEDED(hr)) {
            hr = shellLink->SetArguments(L"");
            if (SUCCEEDED(hr)) {
                hr = shellLink->SetWorkingDirectory(exePath);
                if (SUCCEEDED(hr)) {
                    ComPtr<IPropertyStore> propertyStore;
                    hr = shellLink.As(&propertyStore);
                    if (SUCCEEDED(hr)) {
                        PROPVARIANT appIdPropVar;
                        hr = InitPropVariantFromString(_aumi.c_str(), &appIdPropVar);
                        if (SUCCEEDED(hr)) {
                            hr = propertyStore->SetValue(PKEY_AppUserModel_ID, appIdPropVar);
                            if (SUCCEEDED(hr)) {
                                hr = propertyStore->Commit();
                                if (SUCCEEDED(hr)) {
                                    ComPtr<IPersistFile> persistFile;
                                    hr = shellLink.As(&persistFile);
                                    if (SUCCEEDED(hr)) {
                                        hr = persistFile->Save(slPath, TRUE);
                                    }
                                }
                            }
                        }
                        PropVariantClear(&appIdPropVar);
                    }
                }
            }
        }
    }
    CoTaskMemFree(exePath);
    CoTaskMemFree(slPath);
    return hr;
}

bool WinToast::showToast(_In_ WinToastTemplate& toast)  {
    if (!isInitialized()) {
        std::wcout << "Error when launching the toast. WinToast is not initialized =(" << std::endl;
        return _isInitialized;
    }

    HRESULT hr = _notificationManager->GetTemplateContent(ToastTemplateType(toast.type()), &_xmlDocument);
    if (SUCCEEDED(hr)) {
        for (int i = 0; i < toast.textFieldsCount() && SUCCEEDED(hr); i++) {
            hr = setTextField(toast.textField(i), i);
        }
        if (SUCCEEDED(hr)) {
            hr = toast.hasImage() ? setImageField(toast.imagePath()) : hr;
            if (SUCCEEDED(hr)) {
                hr = _notificationFactory->CreateToastNotification(xmlDocument(), &_notification);
                if (SUCCEEDED(hr)) {
                    hr = Util::setEventHandlers(notification(), toast.handler());
                    if (SUCCEEDED(hr)) {
                        hr = _notifier->Show(notification());
                        if (SUCCEEDED(hr)) {
                        }
                    }
                }
            }
        }
    }

    return SUCCEEDED(hr);
}

HRESULT WinToast::setTextField(_In_ const std::wstring& text, int pos) {
    ComPtr<IXmlNodeList> nodeList;
    HRESULT hr = _xmlDocument->GetElementsByTagName(WinToastStringWrapper(L"text").Get(), &nodeList);
    if (SUCCEEDED(hr)) {
        ComPtr<IXmlNode> node;
        hr = nodeList->Item(pos, &node);
        if (SUCCEEDED(hr)) {
            hr = Util::setNodeStringValue(text, node.Get(), xmlDocument());
        }
    }
    return hr;
}

HRESULT WinToast::setImageField(_In_ const std::wstring& path)  {
    wchar_t imagePath[MAX_PATH] = L"file:///";
    HRESULT hr = StringCchCat(imagePath, MAX_PATH, path.c_str());
    if (SUCCEEDED(hr)) {
        ComPtr<IXmlNodeList> nodeList;
        HRESULT hr = _xmlDocument->GetElementsByTagName(WinToastStringWrapper(L"image").Get(), &nodeList);
        if (SUCCEEDED(hr)) {
            ComPtr<IXmlNode> node;
            hr = nodeList->Item(0, &node);
            if (SUCCEEDED(hr))  {
                ComPtr<IXmlNamedNodeMap> attributes;
                hr = node->get_Attributes(&attributes);
                if (SUCCEEDED(hr)) {
                    ComPtr<IXmlNode> editedNode;
                    hr = attributes->GetNamedItem(WinToastStringWrapper(L"src").Get(), &editedNode);
                    if (SUCCEEDED(hr)) {
                        Util::setNodeStringValue(imagePath, editedNode.Get(), xmlDocument());
                    }
                }
            }
        }
    }
    return hr;
}

WinToastTemplate::WinToastTemplate(const WinToastTemplateType& type) :
    _type(type)
{
    initComponentsFromType();
}

WinToastTemplate::~WinToastTemplate()
{
    _textFields.clear();
}

WinToastHandler *WinToastTemplate::handler() const
{
    return new WinToastHandler;
}

void WinToastTemplate::setTextField(const std::wstring& txt, int pos) {
    _textFields[pos] = txt;
}
void WinToastTemplate::setImagePath(const std::wstring& imgPath) {
    if (!_hasImage)
        return;
    _imagePath = imgPath;
}

void WinToastTemplate::initComponentsFromType() {
    _hasImage = _type < ToastTemplateType_ToastText01;
    _textFieldsCount = (_hasImage ? _type : _type - ToastTemplateType_ToastText01) + 1;
    _textFields = std::vector<std::wstring>(_textFieldsCount, L"");
}

WinToastHandler::WinToastHandler(_In_ HWND hToActivate, _In_ HWND hEdit) :
    _ref(1),
    _hToActivate(hToActivate),
    _hEdit(hEdit)
{
}

WinToastHandler::~WinToastHandler()
{
}

IFACEMETHODIMP WinToastHandler::QueryInterface(_In_ REFIID riid, _COM_Outptr_ void **ppv) {
    if (IsEqualIID(riid, IID_IUnknown))
        *ppv = static_cast<IUnknown*>(static_cast<ToastActivatedEventHandler*>(this));
    else if (IsEqualIID(riid, __uuidof(ToastActivatedEventHandler)))
        *ppv = static_cast<ToastActivatedEventHandler*>(this);
    else if (IsEqualIID(riid, __uuidof(ToastActivatedEventHandler)))
        *ppv = static_cast<ToastDismissedEventHandler*>(this);
    else if (IsEqualIID(riid, __uuidof(ToastFailedEventHandler)))
        *ppv = static_cast<ToastFailedEventHandler*>(this);
    else *ppv = nullptr;

    if (*ppv) {
        reinterpret_cast<IUnknown*>(*ppv)->AddRef();
        return S_OK;
    }

    return E_NOINTERFACE;
}

void WinToastHandler::toastActivated() const {
    std::wcout << L"The user clicked in this toast" << std::endl;

}

void WinToastHandler::toastFailed() const {
    std::wcout << L"Error showing current toast" << std::endl;
}

void WinToastHandler::toastDismissed(WinToastHandler::WinToastDismissalReason state) const {
    switch (state) {
    case UserCanceled:
        std::wcout << L"The user dismissed this toast" << std::endl;
        break;
    case ApplicationHidden:
        std::wcout <<  L"The application hid the toast using ToastNotifier.hide()" << std::endl;
        break;
    case TimedOut:
        std::wcout << L"The toast has timed out" << std::endl;
        break;
    default:
        std::wcout << L"Toast not activated" << std::endl;
        break;
    }
}

IFACEMETHODIMP_(ULONG) WinToastHandler::AddRef()
{
    return InterlockedIncrement(&_ref);
}

IFACEMETHODIMP_(ULONG) WinToastHandler::Release()
{
    ULONG l = InterlockedDecrement(&_ref);
    if (l == 0) {
        delete this;
    }
    return l;
}

IFACEMETHODIMP WinToastHandler::Invoke(_In_ IToastNotification* /*toast*/, _In_ IToastFailedEventArgs* /*e*/) {
    BOOL succeeded = SetForegroundWindow(_hToActivate);
    toastFailed();
    return succeeded ? S_OK : E_FAIL;
}

IFACEMETHODIMP WinToastHandler::Invoke(_In_ IToastNotification* /*toast*/, _In_ IInspectable* /*instpectable*/) {
    toastActivated();
    return S_OK;
}

IFACEMETHODIMP WinToastHandler::Invoke(_In_ IToastNotification* /*toast*/, _In_ IToastDismissedEventArgs *e)  {
    ToastDismissalReason tdr;
    HRESULT hr = e->get_Reason(&tdr);
    if (SUCCEEDED(hr))
    {
       toastDismissed(static_cast<WinToastDismissalReason>(tdr));
    }
    return hr;
}

HRESULT DllImporter::initialize() {
    HINSTANCE LibShell32 = LoadLibrary(L"SHELL32.DLL");
    HRESULT hr = loadFunctionFromLibrary(LibShell32, "SetCurrentProcessExplicitAppUserModelID", SetCurrentProcessExplicitAppUserModelID);
    if (SUCCEEDED(hr)) {
        HINSTANCE LibPropSys = LoadLibrary(L"PROPSYS.DLL");
        hr = loadFunctionFromLibrary(LibPropSys, "PropVariantToString", PropVariantToString);
        if (SUCCEEDED(hr)) {
            HINSTANCE LibComBase = LoadLibrary(L"COMBASE.DLL");
            return SUCCEEDED(loadFunctionFromLibrary(LibComBase, "RoGetActivationFactory", RoGetActivationFactory))
                    && SUCCEEDED(loadFunctionFromLibrary(LibComBase, "WindowsCreateStringReference", WindowsCreateStringReference))
                    && SUCCEEDED(loadFunctionFromLibrary(LibComBase, "WindowsDeleteString", WindowsDeleteString));
        }
    }
    return hr;
}
<|endoftext|>


<commit_before>/*
 * xares.hpp
 *
 * eXploration module for Autonomous Robotic Embedded Systems
 *
 * author:  Cyril Robin <cyril.robin@laas.fr>
 * created: 2013-09-19
 * license: BSD
 */
#ifndef XARES_HPP
#define XARES_HPP

#include <vector>
//#include <ostream>

//#include "gladys/point.hpp"
#include "gladys/frontier_exploration.hpp"

namespace xares {

/* Decison making for frontier attirbutes :
 *
 * Use to sort attributes (thus frontiers) to plan exploration.
 * The lesser, the better.
 *
 */
struct {//{{{
    bool operator()( gladys::f_attributes l, gladys::f_attributes r) {

        // First criteria is proximity (the lesser, the better)
        if (l.proximity == r.proximity ) {
            // 2nd & 3rd criterias are :
            // - size (the bigger, the better)
            // - and cost (distance) : the cheaper, the better
            // We use a ratio
            //return (r.size * r.size * l.distance ) < ( l.size * l.size * r.distance );
            return (r.size * l.distance ) < ( l.size * r.distance );
        }
        return l.proximity < r.proximity ;
    }
} decision_making;//}}}

/*{{{ xares class
 ****************************************************************************/
/* xares class */
class xares{//{{{

private :
    /* internal data */
    gladys::frontier_detector fd ;                      // use to compute frontiers

    std::vector< gladys::points_t > frontiers ;         // the list of the frontiers
    std::vector< gladys::f_attributes > attributes ;    // the frontiers attributes

    gladys::point_xy_t goal ;                           // the current goal chosen by the planner
    gladys::path_t path ;                               // the path to the goal

    /* internal parameters */
    size_t max_nf = 10 ;                                // max nbr of frontiers to consider
    size_t min_size = 2 ;                               // minimal size of the frontier to consider
    gladys::frontier_detector::algo_t algo = gladys::frontier_detector::WFD ; // algo use to compute frontiers

    /* hidden computing functions */

public:
    xares () ;
    /** xares constructor
     *
     * Create a frontier_detector which loads region and robot model
     *
     * @param f_region path to a region.tif file
     * (multi-layers terrains classification probabilities, float32)
     *
     * @param f_robot_model to generate the weight map (at least its size)
     *
     */
    xares( const std::string& f_region, const std::string& f_robot_model ) ;

    /** load a new frontier detect
     *
     * Reset internal data (keep the internal parameters)
     *
     * @param f_region path to a region.tif file
     * (multi-layers terrains classification probabilities, float32)
     *
     * @param f_robot_model to generate the weight map (at least its size)
     *
     */
    void load( const std::string& f_region, const std::string& f_robot_model ) ;

    /** set the internal parameters
     *
     * Keep the internal data.
     *
     * @param _max_nf : max nbr of frontiers to consider
     *
     * @param _min_size : minimal size of the frontier to consider
     *
     * @param _algo : algo use to compute frontiers
     *
     */
    void set_params(//{{{
        size_t _max_nf = 10,
        size_t _min_size = 2,
        gladys::frontier_detector::algo_t _algo = gladys::frontier_detector::WFD
    ){
        max_nf      = _max_nf ;
        min_size    = _min_size ;
        algo        = _algo ;
    }//}}}

    /** plan a goal and a path
     *
     * Compute the frontiers with the given algorithm and parameters.
     * Compute their attributes.
     * Choose a goal.
     *
     * @param r_pos : the position of all the robot in the team. The first one
     * is assume to be the robot running the algorithm.
     *
     */
    void plan( const gladys::points_t &r_pos) ;

    /* getters */
    const std::vector< gladys::f_attributes >&  get_attributes() const {//{{{
        return attributes;
    }//}}}
    const gladys::point_xy_t& get_goal() const {//{{{
        return goal;
    }//}}}
    const gladys::path_t& get_path() const {//{{{
        return path;
    }//}}}

};//}}}

} // namespace  xares

#endif // XARES_HPP

<commit_msg>[xares] Getter for the local references of the map<commit_after>/*
 * xares.hpp
 *
 * eXploration module for Autonomous Robotic Embedded Systems
 *
 * author:  Cyril Robin <cyril.robin@laas.fr>
 * created: 2013-09-19
 * license: BSD
 */
#ifndef XARES_HPP
#define XARES_HPP

#include <vector>
//#include <ostream>

//#include "gladys/point.hpp"
#include "gladys/frontier_exploration.hpp"

namespace xares {

/* Decison making for frontier attirbutes :
 *
 * Use to sort attributes (thus frontiers) to plan exploration.
 * The lesser, the better.
 *
 */
struct {//{{{
    bool operator()( gladys::f_attributes l, gladys::f_attributes r) {

        // First criteria is proximity (the lesser, the better)
        if (l.proximity == r.proximity ) {
            // 2nd & 3rd criterias are :
            // - size (the bigger, the better)
            // - and cost (distance) : the cheaper, the better
            // We use a ratio
            //return (r.size * r.size * l.distance ) < ( l.size * l.size * r.distance );
            return (r.size * l.distance ) < ( l.size * r.distance );
        }
        return l.proximity < r.proximity ;
    }
} decision_making;//}}}

/*{{{ xares class
 ****************************************************************************/
/* xares class */
class xares{//{{{

private :
    /* internal data */
    gladys::frontier_detector fd ;                      // use to compute frontiers

    std::vector< gladys::points_t > frontiers ;         // the list of the frontiers
    std::vector< gladys::f_attributes > attributes ;    // the frontiers attributes

    gladys::point_xy_t goal ;                           // the current goal chosen by the planner
    gladys::path_t path ;                               // the path to the goal

    /* internal parameters */
    size_t max_nf = 10 ;                                // max nbr of frontiers to consider
    size_t min_size = 2 ;                               // minimal size of the frontier to consider
    gladys::frontier_detector::algo_t algo = gladys::frontier_detector::WFD ; // algo use to compute frontiers

    /* hidden computing functions */

public:
    xares () ;
    /** xares constructor
     *
     * Create a frontier_detector which loads region and robot model
     *
     * @param f_region path to a region.tif file
     * (multi-layers terrains classification probabilities, float32)
     *
     * @param f_robot_model to generate the weight map (at least its size)
     *
     */
    xares( const std::string& f_region, const std::string& f_robot_model ) ;

    /** load a new frontier detect
     *
     * Reset internal data (keep the internal parameters)
     *
     * @param f_region path to a region.tif file
     * (multi-layers terrains classification probabilities, float32)
     *
     * @param f_robot_model to generate the weight map (at least its size)
     *
     */
    void load( const std::string& f_region, const std::string& f_robot_model ) ;

    /** set the internal parameters
     *
     * Keep the internal data.
     *
     * @param _max_nf : max nbr of frontiers to consider
     *
     * @param _min_size : minimal size of the frontier to consider
     *
     * @param _algo : algo use to compute frontiers
     *
     */
    void set_params(//{{{
        size_t _max_nf = 10,
        size_t _min_size = 2,
        gladys::frontier_detector::algo_t _algo = gladys::frontier_detector::WFD
    ){
        max_nf      = _max_nf ;
        min_size    = _min_size ;
        algo        = _algo ;
    }//}}}

    /** plan a goal and a path
     *
     * Compute the frontiers with the given algorithm and parameters.
     * Compute their attributes.
     * Choose a goal.
     *
     * @param r_pos : the position of all the robot in the team. The first one
     * is assume to be the robot running the algorithm.
     *
     */
    void plan( const gladys::points_t &r_pos) ;

    /* getters */
    std::array<double, 4> get_transform() const {//{{{
        //TODO take "North up" into account
        std::array<double, 4> transform;
        const gladys::weight_map& map = fd.get_graph().get_map() ;

        transform[0] = map.get_scale_x() ;
        transform[1] = map.get_scale_y() ;
        transform[2] = map.get_utm_pose_x() ;
        transform[3] = map.get_utm_pose_y() ;

        return transform;
    }//}}}
    const std::vector< gladys::f_attributes >&  get_attributes() const {//{{{
        return attributes;
    }//}}}
    const gladys::point_xy_t& get_goal() const {//{{{
        return goal;
    }//}}}
    const gladys::path_t& get_path() const {//{{{
        return path;
    }//}}}

};//}}}

} // namespace  xares

#endif // XARES_HPP

<|endoftext|>