<commit_before>//===- CXComment.cpp - libclang APIs for manipulating CXComments ----------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines all libclang APIs related to walking comment AST.
//
//===----------------------------------------------------------------------===//

#include "clang-c/Index.h"
#include "CXComment.h"
#include "CXCursor.h"
#include "CXString.h"
#include "clang/AST/Decl.h"
#include "clang/Index/CommentToXML.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/ErrorHandling.h"
#include <climits>

using namespace clang;
using namespace clang::comments;
using namespace clang::cxcomment;

extern "C" {

enum CXCommentKind clang_Comment_getKind(CXComment CXC) {
  const Comment *C = getASTNode(CXC);
  if (!C)
    return CXComment_Null;

  switch (C->getCommentKind()) {
  case Comment::NoCommentKind:
    return CXComment_Null;

  case Comment::TextCommentKind:
    return CXComment_Text;

  case Comment::InlineCommandCommentKind:
    return CXComment_InlineCommand;

  case Comment::HTMLStartTagCommentKind:
    return CXComment_HTMLStartTag;

  case Comment::HTMLEndTagCommentKind:
    return CXComment_HTMLEndTag;

  case Comment::ParagraphCommentKind:
    return CXComment_Paragraph;

  case Comment::BlockCommandCommentKind:
    return CXComment_BlockCommand;

  case Comment::ParamCommandCommentKind:
    return CXComment_ParamCommand;

  case Comment::TParamCommandCommentKind:
    return CXComment_TParamCommand;

  case Comment::VerbatimBlockCommentKind:
    return CXComment_VerbatimBlockCommand;

  case Comment::VerbatimBlockLineCommentKind:
    return CXComment_VerbatimBlockLine;

  case Comment::VerbatimLineCommentKind:
    return CXComment_VerbatimLine;

  case Comment::FullCommentKind:
    return CXComment_FullComment;
  }
  llvm_unreachable("unknown CommentKind");
}

unsigned clang_Comment_getNumChildren(CXComment CXC) {
  const Comment *C = getASTNode(CXC);
  if (!C)
    return 0;

  return C->child_count();
}

CXComment clang_Comment_getChild(CXComment CXC, unsigned ChildIdx) {
  const Comment *C = getASTNode(CXC);
  if (!C || ChildIdx >= C->child_count())
    return createCXComment(NULL, NULL);

  return createCXComment(*(C->child_begin() + ChildIdx), CXC.TranslationUnit);
}

unsigned clang_Comment_isWhitespace(CXComment CXC) {
  const Comment *C = getASTNode(CXC);
  if (!C)
    return false;

  if (const TextComment *TC = dyn_cast<TextComment>(C))
    return TC->isWhitespace();

  if (const ParagraphComment *PC = dyn_cast<ParagraphComment>(C))
    return PC->isWhitespace();

  return false;
}

unsigned clang_InlineContentComment_hasTrailingNewline(CXComment CXC) {
  const InlineContentComment *ICC = getASTNodeAs<InlineContentComment>(CXC);
  if (!ICC)
    return false;

  return ICC->hasTrailingNewline();
}

CXString clang_TextComment_getText(CXComment CXC) {
  const TextComment *TC = getASTNodeAs<TextComment>(CXC);
  if (!TC)
    return cxstring::createNull();

  return cxstring::createRef(TC->getText());
}

CXString clang_InlineCommandComment_getCommandName(CXComment CXC) {
  const InlineCommandComment *ICC = getASTNodeAs<InlineCommandComment>(CXC);
  if (!ICC)
    return cxstring::createNull();

  const CommandTraits &Traits = getCommandTraits(CXC);
  return cxstring::createRef(ICC->getCommandName(Traits));
}

enum CXCommentInlineCommandRenderKind
clang_InlineCommandComment_getRenderKind(CXComment CXC) {
  const InlineCommandComment *ICC = getASTNodeAs<InlineCommandComment>(CXC);
  if (!ICC)
    return CXCommentInlineCommandRenderKind_Normal;

  switch (ICC->getRenderKind()) {
  case InlineCommandComment::RenderNormal:
    return CXCommentInlineCommandRenderKind_Normal;

  case InlineCommandComment::RenderBold:
    return CXCommentInlineCommandRenderKind_Bold;

  case InlineCommandComment::RenderMonospaced:
    return CXCommentInlineCommandRenderKind_Monospaced;

  case InlineCommandComment::RenderEmphasized:
    return CXCommentInlineCommandRenderKind_Emphasized;
  }
  llvm_unreachable("unknown InlineCommandComment::RenderKind");
}

unsigned clang_InlineCommandComment_getNumArgs(CXComment CXC) {
  const InlineCommandComment *ICC = getASTNodeAs<InlineCommandComment>(CXC);
  if (!ICC)
    return 0;

  return ICC->getNumArgs();
}

CXString clang_InlineCommandComment_getArgText(CXComment CXC,
                                               unsigned ArgIdx) {
  const InlineCommandComment *ICC = getASTNodeAs<InlineCommandComment>(CXC);
  if (!ICC || ArgIdx >= ICC->getNumArgs())
    return cxstring::createNull();

  return cxstring::createRef(ICC->getArgText(ArgIdx));
}

CXString clang_HTMLTagComment_getTagName(CXComment CXC) {
  const HTMLTagComment *HTC = getASTNodeAs<HTMLTagComment>(CXC);
  if (!HTC)
    return cxstring::createNull();

  return cxstring::createRef(HTC->getTagName());
}

unsigned clang_HTMLStartTagComment_isSelfClosing(CXComment CXC) {
  const HTMLStartTagComment *HST = getASTNodeAs<HTMLStartTagComment>(CXC);
  if (!HST)
    return false;

  return HST->isSelfClosing();
}

unsigned clang_HTMLStartTag_getNumAttrs(CXComment CXC) {
  const HTMLStartTagComment *HST = getASTNodeAs<HTMLStartTagComment>(CXC);
  if (!HST)
    return 0;

  return HST->getNumAttrs();
}

CXString clang_HTMLStartTag_getAttrName(CXComment CXC, unsigned AttrIdx) {
  const HTMLStartTagComment *HST = getASTNodeAs<HTMLStartTagComment>(CXC);
  if (!HST || AttrIdx >= HST->getNumAttrs())
    return cxstring::createNull();

  return cxstring::createRef(HST->getAttr(AttrIdx).Name);
}

CXString clang_HTMLStartTag_getAttrValue(CXComment CXC, unsigned AttrIdx) {
  const HTMLStartTagComment *HST = getASTNodeAs<HTMLStartTagComment>(CXC);
  if (!HST || AttrIdx >= HST->getNumAttrs())
    return cxstring::createNull();

  return cxstring::createRef(HST->getAttr(AttrIdx).Value);
}

CXString clang_BlockCommandComment_getCommandName(CXComment CXC) {
  const BlockCommandComment *BCC = getASTNodeAs<BlockCommandComment>(CXC);
  if (!BCC)
    return cxstring::createNull();

  const CommandTraits &Traits = getCommandTraits(CXC);
  return cxstring::createRef(BCC->getCommandName(Traits));
}

unsigned clang_BlockCommandComment_getNumArgs(CXComment CXC) {
  const BlockCommandComment *BCC = getASTNodeAs<BlockCommandComment>(CXC);
  if (!BCC)
    return 0;

  return BCC->getNumArgs();
}

CXString clang_BlockCommandComment_getArgText(CXComment CXC,
                                              unsigned ArgIdx) {
  const BlockCommandComment *BCC = getASTNodeAs<BlockCommandComment>(CXC);
  if (!BCC || ArgIdx >= BCC->getNumArgs())
    return cxstring::createNull();

  return cxstring::createRef(BCC->getArgText(ArgIdx));
}

CXComment clang_BlockCommandComment_getParagraph(CXComment CXC) {
  const BlockCommandComment *BCC = getASTNodeAs<BlockCommandComment>(CXC);
  if (!BCC)
    return createCXComment(NULL, NULL);

  return createCXComment(BCC->getParagraph(), CXC.TranslationUnit);
}

CXString clang_ParamCommandComment_getParamName(CXComment CXC) {
  const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC);
  if (!PCC || !PCC->hasParamName())
    return cxstring::createNull();

  return cxstring::createRef(PCC->getParamNameAsWritten());
}

unsigned clang_ParamCommandComment_isParamIndexValid(CXComment CXC) {
  const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC);
  if (!PCC)
    return false;

  return PCC->isParamIndexValid();
}

unsigned clang_ParamCommandComment_getParamIndex(CXComment CXC) {
  const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC);
  if (!PCC || !PCC->isParamIndexValid() || PCC->isVarArgParam())
    return ParamCommandComment::InvalidParamIndex;

  return PCC->getParamIndex();
}

unsigned clang_ParamCommandComment_isDirectionExplicit(CXComment CXC) {
  const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC);
  if (!PCC)
    return false;

  return PCC->isDirectionExplicit();
}

enum CXCommentParamPassDirection clang_ParamCommandComment_getDirection(
                                                            CXComment CXC) {
  const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC);
  if (!PCC)
    return CXCommentParamPassDirection_In;

  switch (PCC->getDirection()) {
  case ParamCommandComment::In:
    return CXCommentParamPassDirection_In;

  case ParamCommandComment::Out:
    return CXCommentParamPassDirection_Out;

  case ParamCommandComment::InOut:
    return CXCommentParamPassDirection_InOut;
  }
  llvm_unreachable("unknown ParamCommandComment::PassDirection");
}

CXString clang_TParamCommandComment_getParamName(CXComment CXC) {
  const TParamCommandComment *TPCC = getASTNodeAs<TParamCommandComment>(CXC);
  if (!TPCC || !TPCC->hasParamName())
    return cxstring::createNull();

  return cxstring::createRef(TPCC->getParamNameAsWritten());
}

unsigned clang_TParamCommandComment_isParamPositionValid(CXComment CXC) {
  const TParamCommandComment *TPCC = getASTNodeAs<TParamCommandComment>(CXC);
  if (!TPCC)
    return false;

  return TPCC->isPositionValid();
}

unsigned clang_TParamCommandComment_getDepth(CXComment CXC) {
  const TParamCommandComment *TPCC = getASTNodeAs<TParamCommandComment>(CXC);
  if (!TPCC || !TPCC->isPositionValid())
    return 0;

  return TPCC->getDepth();
}

unsigned clang_TParamCommandComment_getIndex(CXComment CXC, unsigned Depth) {
  const TParamCommandComment *TPCC = getASTNodeAs<TParamCommandComment>(CXC);
  if (!TPCC || !TPCC->isPositionValid() || Depth >= TPCC->getDepth())
    return 0;

  return TPCC->getIndex(Depth);
}

CXString clang_VerbatimBlockLineComment_getText(CXComment CXC) {
  const VerbatimBlockLineComment *VBL =
      getASTNodeAs<VerbatimBlockLineComment>(CXC);
  if (!VBL)
    return cxstring::createNull();

  return cxstring::createRef(VBL->getText());
}

CXString clang_VerbatimLineComment_getText(CXComment CXC) {
  const VerbatimLineComment *VLC = getASTNodeAs<VerbatimLineComment>(CXC);
  if (!VLC)
    return cxstring::createNull();

  return cxstring::createRef(VLC->getText());
}

//===----------------------------------------------------------------------===//
// Converting comments to XML.
//===----------------------------------------------------------------------===//

CXString clang_HTMLTagComment_getAsString(CXComment CXC) {
  const HTMLTagComment *HTC = getASTNodeAs<HTMLTagComment>(CXC);
  if (!HTC)
    return cxstring::createNull();

  CXTranslationUnit TU = CXC.TranslationUnit;
  if (!TU->CommentToXML)
    TU->CommentToXML = new index::CommentToXMLConverter();

  SmallString<128> Text;
  TU->CommentToXML->convertHTMLTagNodeToText(
      HTC, Text, cxtu::getASTUnit(TU)->getASTContext());
  return cxstring::createDup(Text.str());
}

CXString clang_FullComment_getAsHTML(CXComment CXC) {
  const FullComment *FC = getASTNodeAs<FullComment>(CXC);
  if (!FC)
    return cxstring::createNull();

  CXTranslationUnit TU = CXC.TranslationUnit;
  if (!TU->CommentToXML)
    TU->CommentToXML = new index::CommentToXMLConverter();

  SmallString<1024> HTML;
  TU->CommentToXML
      ->convertCommentToHTML(FC, HTML, cxtu::getASTUnit(TU)->getASTContext());
  return cxstring::createDup(HTML.str());
}

CXString clang_FullComment_getAsXML(CXComment CXC) {
  const FullComment *FC = getASTNodeAs<FullComment>(CXC);
  if (!FC)
    return cxstring::createNull();

  CXTranslationUnit TU = CXC.TranslationUnit;
  if (!TU->CommentToXML)
    TU->CommentToXML = new index::CommentToXMLConverter();

  SmallString<1024> XML;
  TU->CommentToXML
      ->convertCommentToXML(FC, XML, cxtu::getASTUnit(TU)->getASTContext());
  return cxstring::createDup(XML.str());
}

} // end extern "C"

<commit_msg>Work around a bug in old gcc on the FreeBSD bot, which complains about ambiguity between index() function and clang::index namespace.<commit_after>//===- CXComment.cpp - libclang APIs for manipulating CXComments ----------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines all libclang APIs related to walking comment AST.
//
//===----------------------------------------------------------------------===//

#include "clang-c/Index.h"
#include "CXComment.h"
#include "CXCursor.h"
#include "CXString.h"
#include "clang/AST/Decl.h"
#include "clang/Index/CommentToXML.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/ErrorHandling.h"
#include <climits>

using namespace clang;
using namespace clang::comments;
using namespace clang::cxcomment;

extern "C" {

enum CXCommentKind clang_Comment_getKind(CXComment CXC) {
  const Comment *C = getASTNode(CXC);
  if (!C)
    return CXComment_Null;

  switch (C->getCommentKind()) {
  case Comment::NoCommentKind:
    return CXComment_Null;

  case Comment::TextCommentKind:
    return CXComment_Text;

  case Comment::InlineCommandCommentKind:
    return CXComment_InlineCommand;

  case Comment::HTMLStartTagCommentKind:
    return CXComment_HTMLStartTag;

  case Comment::HTMLEndTagCommentKind:
    return CXComment_HTMLEndTag;

  case Comment::ParagraphCommentKind:
    return CXComment_Paragraph;

  case Comment::BlockCommandCommentKind:
    return CXComment_BlockCommand;

  case Comment::ParamCommandCommentKind:
    return CXComment_ParamCommand;

  case Comment::TParamCommandCommentKind:
    return CXComment_TParamCommand;

  case Comment::VerbatimBlockCommentKind:
    return CXComment_VerbatimBlockCommand;

  case Comment::VerbatimBlockLineCommentKind:
    return CXComment_VerbatimBlockLine;

  case Comment::VerbatimLineCommentKind:
    return CXComment_VerbatimLine;

  case Comment::FullCommentKind:
    return CXComment_FullComment;
  }
  llvm_unreachable("unknown CommentKind");
}

unsigned clang_Comment_getNumChildren(CXComment CXC) {
  const Comment *C = getASTNode(CXC);
  if (!C)
    return 0;

  return C->child_count();
}

CXComment clang_Comment_getChild(CXComment CXC, unsigned ChildIdx) {
  const Comment *C = getASTNode(CXC);
  if (!C || ChildIdx >= C->child_count())
    return createCXComment(NULL, NULL);

  return createCXComment(*(C->child_begin() + ChildIdx), CXC.TranslationUnit);
}

unsigned clang_Comment_isWhitespace(CXComment CXC) {
  const Comment *C = getASTNode(CXC);
  if (!C)
    return false;

  if (const TextComment *TC = dyn_cast<TextComment>(C))
    return TC->isWhitespace();

  if (const ParagraphComment *PC = dyn_cast<ParagraphComment>(C))
    return PC->isWhitespace();

  return false;
}

unsigned clang_InlineContentComment_hasTrailingNewline(CXComment CXC) {
  const InlineContentComment *ICC = getASTNodeAs<InlineContentComment>(CXC);
  if (!ICC)
    return false;

  return ICC->hasTrailingNewline();
}

CXString clang_TextComment_getText(CXComment CXC) {
  const TextComment *TC = getASTNodeAs<TextComment>(CXC);
  if (!TC)
    return cxstring::createNull();

  return cxstring::createRef(TC->getText());
}

CXString clang_InlineCommandComment_getCommandName(CXComment CXC) {
  const InlineCommandComment *ICC = getASTNodeAs<InlineCommandComment>(CXC);
  if (!ICC)
    return cxstring::createNull();

  const CommandTraits &Traits = getCommandTraits(CXC);
  return cxstring::createRef(ICC->getCommandName(Traits));
}

enum CXCommentInlineCommandRenderKind
clang_InlineCommandComment_getRenderKind(CXComment CXC) {
  const InlineCommandComment *ICC = getASTNodeAs<InlineCommandComment>(CXC);
  if (!ICC)
    return CXCommentInlineCommandRenderKind_Normal;

  switch (ICC->getRenderKind()) {
  case InlineCommandComment::RenderNormal:
    return CXCommentInlineCommandRenderKind_Normal;

  case InlineCommandComment::RenderBold:
    return CXCommentInlineCommandRenderKind_Bold;

  case InlineCommandComment::RenderMonospaced:
    return CXCommentInlineCommandRenderKind_Monospaced;

  case InlineCommandComment::RenderEmphasized:
    return CXCommentInlineCommandRenderKind_Emphasized;
  }
  llvm_unreachable("unknown InlineCommandComment::RenderKind");
}

unsigned clang_InlineCommandComment_getNumArgs(CXComment CXC) {
  const InlineCommandComment *ICC = getASTNodeAs<InlineCommandComment>(CXC);
  if (!ICC)
    return 0;

  return ICC->getNumArgs();
}

CXString clang_InlineCommandComment_getArgText(CXComment CXC,
                                               unsigned ArgIdx) {
  const InlineCommandComment *ICC = getASTNodeAs<InlineCommandComment>(CXC);
  if (!ICC || ArgIdx >= ICC->getNumArgs())
    return cxstring::createNull();

  return cxstring::createRef(ICC->getArgText(ArgIdx));
}

CXString clang_HTMLTagComment_getTagName(CXComment CXC) {
  const HTMLTagComment *HTC = getASTNodeAs<HTMLTagComment>(CXC);
  if (!HTC)
    return cxstring::createNull();

  return cxstring::createRef(HTC->getTagName());
}

unsigned clang_HTMLStartTagComment_isSelfClosing(CXComment CXC) {
  const HTMLStartTagComment *HST = getASTNodeAs<HTMLStartTagComment>(CXC);
  if (!HST)
    return false;

  return HST->isSelfClosing();
}

unsigned clang_HTMLStartTag_getNumAttrs(CXComment CXC) {
  const HTMLStartTagComment *HST = getASTNodeAs<HTMLStartTagComment>(CXC);
  if (!HST)
    return 0;

  return HST->getNumAttrs();
}

CXString clang_HTMLStartTag_getAttrName(CXComment CXC, unsigned AttrIdx) {
  const HTMLStartTagComment *HST = getASTNodeAs<HTMLStartTagComment>(CXC);
  if (!HST || AttrIdx >= HST->getNumAttrs())
    return cxstring::createNull();

  return cxstring::createRef(HST->getAttr(AttrIdx).Name);
}

CXString clang_HTMLStartTag_getAttrValue(CXComment CXC, unsigned AttrIdx) {
  const HTMLStartTagComment *HST = getASTNodeAs<HTMLStartTagComment>(CXC);
  if (!HST || AttrIdx >= HST->getNumAttrs())
    return cxstring::createNull();

  return cxstring::createRef(HST->getAttr(AttrIdx).Value);
}

CXString clang_BlockCommandComment_getCommandName(CXComment CXC) {
  const BlockCommandComment *BCC = getASTNodeAs<BlockCommandComment>(CXC);
  if (!BCC)
    return cxstring::createNull();

  const CommandTraits &Traits = getCommandTraits(CXC);
  return cxstring::createRef(BCC->getCommandName(Traits));
}

unsigned clang_BlockCommandComment_getNumArgs(CXComment CXC) {
  const BlockCommandComment *BCC = getASTNodeAs<BlockCommandComment>(CXC);
  if (!BCC)
    return 0;

  return BCC->getNumArgs();
}

CXString clang_BlockCommandComment_getArgText(CXComment CXC,
                                              unsigned ArgIdx) {
  const BlockCommandComment *BCC = getASTNodeAs<BlockCommandComment>(CXC);
  if (!BCC || ArgIdx >= BCC->getNumArgs())
    return cxstring::createNull();

  return cxstring::createRef(BCC->getArgText(ArgIdx));
}

CXComment clang_BlockCommandComment_getParagraph(CXComment CXC) {
  const BlockCommandComment *BCC = getASTNodeAs<BlockCommandComment>(CXC);
  if (!BCC)
    return createCXComment(NULL, NULL);

  return createCXComment(BCC->getParagraph(), CXC.TranslationUnit);
}

CXString clang_ParamCommandComment_getParamName(CXComment CXC) {
  const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC);
  if (!PCC || !PCC->hasParamName())
    return cxstring::createNull();

  return cxstring::createRef(PCC->getParamNameAsWritten());
}

unsigned clang_ParamCommandComment_isParamIndexValid(CXComment CXC) {
  const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC);
  if (!PCC)
    return false;

  return PCC->isParamIndexValid();
}

unsigned clang_ParamCommandComment_getParamIndex(CXComment CXC) {
  const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC);
  if (!PCC || !PCC->isParamIndexValid() || PCC->isVarArgParam())
    return ParamCommandComment::InvalidParamIndex;

  return PCC->getParamIndex();
}

unsigned clang_ParamCommandComment_isDirectionExplicit(CXComment CXC) {
  const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC);
  if (!PCC)
    return false;

  return PCC->isDirectionExplicit();
}

enum CXCommentParamPassDirection clang_ParamCommandComment_getDirection(
                                                            CXComment CXC) {
  const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC);
  if (!PCC)
    return CXCommentParamPassDirection_In;

  switch (PCC->getDirection()) {
  case ParamCommandComment::In:
    return CXCommentParamPassDirection_In;

  case ParamCommandComment::Out:
    return CXCommentParamPassDirection_Out;

  case ParamCommandComment::InOut:
    return CXCommentParamPassDirection_InOut;
  }
  llvm_unreachable("unknown ParamCommandComment::PassDirection");
}

CXString clang_TParamCommandComment_getParamName(CXComment CXC) {
  const TParamCommandComment *TPCC = getASTNodeAs<TParamCommandComment>(CXC);
  if (!TPCC || !TPCC->hasParamName())
    return cxstring::createNull();

  return cxstring::createRef(TPCC->getParamNameAsWritten());
}

unsigned clang_TParamCommandComment_isParamPositionValid(CXComment CXC) {
  const TParamCommandComment *TPCC = getASTNodeAs<TParamCommandComment>(CXC);
  if (!TPCC)
    return false;

  return TPCC->isPositionValid();
}

unsigned clang_TParamCommandComment_getDepth(CXComment CXC) {
  const TParamCommandComment *TPCC = getASTNodeAs<TParamCommandComment>(CXC);
  if (!TPCC || !TPCC->isPositionValid())
    return 0;

  return TPCC->getDepth();
}

unsigned clang_TParamCommandComment_getIndex(CXComment CXC, unsigned Depth) {
  const TParamCommandComment *TPCC = getASTNodeAs<TParamCommandComment>(CXC);
  if (!TPCC || !TPCC->isPositionValid() || Depth >= TPCC->getDepth())
    return 0;

  return TPCC->getIndex(Depth);
}

CXString clang_VerbatimBlockLineComment_getText(CXComment CXC) {
  const VerbatimBlockLineComment *VBL =
      getASTNodeAs<VerbatimBlockLineComment>(CXC);
  if (!VBL)
    return cxstring::createNull();

  return cxstring::createRef(VBL->getText());
}

CXString clang_VerbatimLineComment_getText(CXComment CXC) {
  const VerbatimLineComment *VLC = getASTNodeAs<VerbatimLineComment>(CXC);
  if (!VLC)
    return cxstring::createNull();

  return cxstring::createRef(VLC->getText());
}

//===----------------------------------------------------------------------===//
// Converting comments to XML.
//===----------------------------------------------------------------------===//

CXString clang_HTMLTagComment_getAsString(CXComment CXC) {
  const HTMLTagComment *HTC = getASTNodeAs<HTMLTagComment>(CXC);
  if (!HTC)
    return cxstring::createNull();

  CXTranslationUnit TU = CXC.TranslationUnit;
  if (!TU->CommentToXML)
    TU->CommentToXML = new clang::index::CommentToXMLConverter();

  SmallString<128> Text;
  TU->CommentToXML->convertHTMLTagNodeToText(
      HTC, Text, cxtu::getASTUnit(TU)->getASTContext());
  return cxstring::createDup(Text.str());
}

CXString clang_FullComment_getAsHTML(CXComment CXC) {
  const FullComment *FC = getASTNodeAs<FullComment>(CXC);
  if (!FC)
    return cxstring::createNull();

  CXTranslationUnit TU = CXC.TranslationUnit;
  if (!TU->CommentToXML)
    TU->CommentToXML = new clang::index::CommentToXMLConverter();

  SmallString<1024> HTML;
  TU->CommentToXML
      ->convertCommentToHTML(FC, HTML, cxtu::getASTUnit(TU)->getASTContext());
  return cxstring::createDup(HTML.str());
}

CXString clang_FullComment_getAsXML(CXComment CXC) {
  const FullComment *FC = getASTNodeAs<FullComment>(CXC);
  if (!FC)
    return cxstring::createNull();

  CXTranslationUnit TU = CXC.TranslationUnit;
  if (!TU->CommentToXML)
    TU->CommentToXML = new clang::index::CommentToXMLConverter();

  SmallString<1024> XML;
  TU->CommentToXML
      ->convertCommentToXML(FC, XML, cxtu::getASTUnit(TU)->getASTContext());
  return cxstring::createDup(XML.str());
}

} // end extern "C"

<|endoftext|>


<commit_before>/// @file
/// @author uentity
/// @date 22.09.2017
/// @brief BS tree Python bindings
/// @copyright
/// This Source Code Form is subject to the terms of the Mozilla Public License,
/// v. 2.0. If a copy of the MPL was not distributed with this file,
/// You can obtain one at https://mozilla.org/MPL/2.0/

#include <bs/bs.h>
#include <bs/link.h>
#include <bs/node.h>
#include <boost/uuid/uuid_io.hpp>
#include <boost/uuid/string_generator.hpp>
#include <string>

#include <iostream>

NAMESPACE_BEGIN(blue_sky)
NAMESPACE_BEGIN(python)
using namespace tree;

namespace {

template<typename Link = link>
class py_link : public Link {
public:
	using Link::Link;

	sp_link clone() const override {
		PYBIND11_OVERLOAD_PURE(sp_link, Link, clone, );
	}

	sp_obj data() const override {
		PYBIND11_OVERLOAD_PURE(sp_obj, Link, data, );
	}

	std::string type_id() const override {
		PYBIND11_OVERLOAD_PURE(std::string, Link, type_id, );
	}

	std::string oid() const override {
		PYBIND11_OVERLOAD_PURE(std::string, Link, oid, );
	}

	std::string obj_type_id() const override {
		PYBIND11_OVERLOAD_PURE(std::string, Link, obj_type_id, );
	}

	sp_node data_node() const override {
		PYBIND11_OVERLOAD_PURE(sp_node, Link, data_node, );
	}
};

static boost::uuids::string_generator uuid_from_str;

void print_link(const sp_link& l, int level = 0) {
	static const auto dumplnk = [](const sp_link& l_) {
		std::cout << l_->name() << " -> (" << l_->obj_type_id() << ", " << l_->oid() << ")" << std::endl;
	};

	const std::string loffs(level*2, ' ');
	// print link itself
	std::cout << loffs;
	dumplnk(l);
	if(auto n = l->data_node()) {
		// print leafs
		for(const auto &leaf : *n)
			print_link(leaf, level+1);
	}
}

}

void py_bind_tree(py::module& m) {
	py::class_<inode>(m, "inode")
		.def(py::init<std::string, std::string>())
		.def_readonly("owner", &inode::owner)
		.def_readonly("group", &inode::group)
		.def_property_readonly("suid", [](const inode& i) { return i.suid; })
		.def_property_readonly("sgid", [](const inode& i) { return i.sgid; })
		.def_property_readonly("sticky", [](const inode& i) { return i.sticky; })
		.def_property_readonly("u", [](const inode& i) { return i.u; })
		.def_property_readonly("g", [](const inode& i) { return i.g; })
		.def_property_readonly("o", [](const inode& i) { return i.o; })
	;

	py::class_<link, py_link<>, std::shared_ptr<link>> link_pyface(m, "link");
	link_pyface
		.def(py::init<std::string>())
		.def("clone", &link::clone)
		.def("data", &link::data)
		.def("type_id", &link::type_id)
		.def("oid", &link::oid)
		.def("obj_type_id", &link::obj_type_id)
		.def("data_node", &link::data_node)
		.def_property_readonly("id", [](const link& L) {
			return boost::uuids::to_string(L.id());
		})
		.def_property_readonly("name", &link::name)
		.def_property("inode",
			py::overload_cast<>(&link::get_inode, py::const_),
			py::overload_cast<>(&link::get_inode)
		)
		.def_property_readonly("owner", &link::owner)
	;

	py::class_<hard_link, link, py_link<hard_link>, std::shared_ptr<hard_link>>(m, "hard_link")
		.def(py::init<std::string, sp_obj>())
	;
	py::class_<weak_link, link, py_link<weak_link>, std::shared_ptr<weak_link>>(m, "weak_link")
		.def(py::init<std::string, const sp_obj&>())
	;

	// forward define node
	py::class_<node, objbase, std::shared_ptr<node>> node_pyface(m, "node");

	// export node's Key enum
	py::enum_<node::Key>(node_pyface, "Key")
		.value("ID", node::Key::ID)
		.value("OID", node::Key::OID)
		.value("Name", node::Key::Name)
		.value("Type", node::Key::Type)
	;
	// export node's insert policy
	py::enum_<node::InsertPolicy>(node_pyface, "InsertPolicy")
		.value("AllowDupNames", node::InsertPolicy::AllowDupNames)
		.value("DenyDupNames", node::InsertPolicy::DenyDupNames)
		.value("RenameDup", node::InsertPolicy::RenameDup)
		.value("DenyDupOID", node::InsertPolicy::DenyDupOID)
		.value("Merge", node::InsertPolicy::Merge)
		.export_values();
	;

	// fill node with methods
	node_pyface
		BSPY_EXPORT_DEF(node)
		.def(py::init<>())
		.def("__len__", &node::size)
		.def("__iter__",
			[](const node& N) { return py::make_iterator(N.begin(), N.end()); },
			py::keep_alive<0, 1>()
		)

		// check by link name or object instance (object's ID)
		.def("__contains__", [](const node& N, py::object key) {
			if(PyString_Check(key.ptr()))
				return N.find(py::cast<std::string>(key)) != N.end<>();
			return N.find_oid(py::cast<sp_obj>(key)->id()) != N.end<>();
		})
		// check by link ID
		.def("contains_lid", [](const node& N, const std::string& lid) {
			return N.find(uuid_from_str(lid)) != N.end<>();
		}, "LID", "Check if node contains link with given ID")
		// check by object ID
		.def("contains_oid", [](const node& N, const std::string& oid) {
			return N.find_oid(oid) != N.end<>();
		}, "OID", "Check if node contains object with given ID")
		// check by object type
		.def("contains_type", [](const node& N, const std::string& type_id) {
			return N.equal_type(type_id).first != N.end<node::Key::Type>();
		}, "obj_type_id", "Check if node contains objects with given type")

		// get item by int index
		.def("__getitem__", [](const node& N, const long idx) {
			// support for Pythonish indexing from both ends
			if(std::size_t(std::abs(idx)) > N.size())
				throw py::key_error("Index out of bounds");
			auto pos = idx < 0 ? N.end() : N.begin();
			std::advance(pos, idx);
			if(pos == N.end()) throw py::key_error("Index out of bounds");
			return *pos;
		}, py::return_value_policy::reference_internal, "link_idx"_a)
		// search by link name
		.def("__getitem__", [](const node& N, const std::string& link_name) {
			auto r = N.find(link_name);
			if(r != N.end<>()) return *r;
			throw py::key_error("Node doesn't contain link with name '" + link_name + "'");
		}, py::return_value_policy::reference_internal, "link_name"_a)
		// search by object instance
		.def("__getitem__", [](const node& N, const sp_obj& obj) {
			auto r = N.find(obj->id());
			if(r != N.end<>()) return *r;
			throw py::key_error("Node doesn't contain object with ID = " + obj->id());
		}, py::return_value_policy::reference_internal, "object"_a)
		// search by object ID
		.def("find_oid", [](const node& N, const std::string& oid) {
			auto r = N.find_oid(oid);
			if(r != N.end<>()) return *r;
			throw py::key_error("Node doesn't contain object with ID - " + oid);
		}, py::return_value_policy::reference_internal, "OID"_a, "Find item by object ID")
		// search by link ID
		.def("find_lid", [](const node& N, const std::string& lid) {
			auto r = N.find(uuid_from_str(lid));
			if(r != N.end<>()) return *r;
			throw py::key_error("Node doesn't contain link with ID - " + lid);
		}, py::return_value_policy::reference_internal, "LID"_a, "Find item by object link ID")

		// deep search by link name or object instance (OID)
		.def("deep_search", [](const node& N, py::object key) {
			if(PyString_Check(key.ptr()))
				return N.deep_search(py::cast<std::string>(key));
			return N.deep_search_oid(py::cast<sp_obj>(key)->id());
		}, "key"_a, "Deep search for link with given name or by object instance (OID)")
		.def("deep_search_lid", [](const node& N, const std::string& lid) {
			return N.deep_search(uuid_from_str(lid));
		}, "LID"_a, "Deep search for link with given ID")
		// deep search by object ID
		.def("deep_search_oid", [](const node& N, const std::string& oid) {
			return N.deep_search_oid(oid);
		}, "OID"_a, "Deep search for object with given ID")

		.def("equal_range", [](const node& N, const std::string& link_name) {
			auto r = N.equal_range(link_name);
			return py::make_iterator(r.first, r.second);
		}, py::keep_alive<0, 1>(), "link_name"_a)
		.def("equal_range_oid", [](const node& N, const std::string& oid) {
			auto r = N.equal_range_oid(oid);
			return py::make_iterator(r.first, r.second);
		}, py::keep_alive<0, 1>(), "OID"_a)
		.def("equal_type", [](const node& N, const std::string& type_id) {
			auto r = N.equal_type(type_id);
			return py::make_iterator(r.first, r.second);
		}, py::keep_alive<0, 1>(), "obj_type_id"_a)

		// insert given link
		.def("insert", [](node& N, sp_link l, uint pol = node::AllowDupNames) {
			return N.insert(std::move(l)).second;
		}, "link"_a, "pol"_a = node::AllowDupNames, "Insert given link")
		// insert hard link to given object
		.def("insert", [](node& N, std::string name, sp_obj obj, uint pol = node::AllowDupNames) {
			return N.insert(std::move(name), std::move(obj), pol).second;
		}, "name"_a, "obj"_a, "pol"_a = node::AllowDupNames, "Insert hard link to given object")

		// erase by given index
		.def("__delitem__", [](node& N, const long idx) {
			// support for Pythonish indexing from both ends
			if(std::size_t(std::abs(idx)) > N.size())
				throw py::key_error("Index out of bounds");
			N.erase(idx < 0 ? N.size() + idx : idx);
		})
		// erase by given link name or object instance (object's ID)
		.def("__delitem__", [](node& N, py::object key) {
			if(PyString_Check(key.ptr()))
				N.erase(py::cast<std::string>(key));
			N.erase_oid(py::cast<sp_obj>(key)->id());
		})
		.def("erase", (void (node::*)(const std::string&))&node::erase,
			"link_name"_a, "Erase links with given name")
		.def("erase_oid", &node::erase_oid, "obj"_a, "Erase links to given object")
		.def("erase_lid", [](node& N, const std::string& key) {
			N.erase(uuid_from_str(key));
		}, "lid"_a, "Erase link with given ID")
		.def("erase_type", [](node& N, const std::string& type_id) {
			N.erase_type(type_id);
		}, "obj_type_id"_a, "Erase all links pointing to objects with given type")

		// misc functions
		.def_property_readonly("size", &node::size)
		.def_property_readonly("empty", &node::empty)
		.def("clear", &node::clear, "Clears all node contents")
		.def("keys", [](const node& N, node::Key ktype = node::Key::Name) {
			if(ktype == node::Key::ID) {
				// convert UUIDs to string representation
				auto keys = N.keys<>();
				std::vector<std::string> res;
				res.reserve(keys.size());
				for(const auto& k : keys)
					res.emplace_back(boost::uuids::to_string(k));
				return res;
			}
			else {
				switch(ktype) {
				default:
				case node::Key::Name :
					return N.keys<node::Key::Name>();
				case node::Key::OID :
					return N.keys<node::Key::OID>();
				case node::Key::Type :
					return N.keys<node::Key::Type>();
				};
			}
		}, "key_type"_a = node::Key::Name)
	;

	m.def("print_link", [](const sp_link& l) { print_link(l, 0); });
	m.def("print_link", [](const sp_node& n, std::string name = "/") {
		print_link(std::make_shared<tree::hard_link>(name, n), 0);
	}, "node"_a, "root_name"_a = "/");
}

NAMESPACE_END(python)
NAMESPACE_END(blue_sky)

<commit_msg>node.python: make link's ID a 'default' key for misc operations, update and fix bindings<commit_after>/// @file
/// @author uentity
/// @date 22.09.2017
/// @brief BS tree Python bindings
/// @copyright
/// This Source Code Form is subject to the terms of the Mozilla Public License,
/// v. 2.0. If a copy of the MPL was not distributed with this file,
/// You can obtain one at https://mozilla.org/MPL/2.0/

#include <bs/bs.h>
#include <bs/link.h>
#include <bs/node.h>
#include <boost/uuid/uuid_io.hpp>
#include <boost/uuid/string_generator.hpp>
#include <string>

#include <iostream>

NAMESPACE_BEGIN(blue_sky)
NAMESPACE_BEGIN(python)
using namespace tree;

namespace {

template<typename Link = link>
class py_link : public Link {
public:
	using Link::Link;

	sp_link clone() const override {
		PYBIND11_OVERLOAD_PURE(sp_link, Link, clone, );
	}

	sp_obj data() const override {
		PYBIND11_OVERLOAD_PURE(sp_obj, Link, data, );
	}

	std::string type_id() const override {
		PYBIND11_OVERLOAD_PURE(std::string, Link, type_id, );
	}

	std::string oid() const override {
		PYBIND11_OVERLOAD_PURE(std::string, Link, oid, );
	}

	std::string obj_type_id() const override {
		PYBIND11_OVERLOAD_PURE(std::string, Link, obj_type_id, );
	}

	sp_node data_node() const override {
		PYBIND11_OVERLOAD_PURE(sp_node, Link, data_node, );
	}
};

static boost::uuids::string_generator uuid_from_str;

void print_link(const sp_link& l, int level = 0) {
	static const auto dumplnk = [](const sp_link& l_) {
		std::cout << l_->name() << " -> (" << l_->obj_type_id() << ", " << l_->oid() << ")" << std::endl;
	};

	const std::string loffs(level*2, ' ');
	// print link itself
	std::cout << loffs;
	dumplnk(l);
	if(auto n = l->data_node()) {
		// print leafs
		for(const auto &leaf : *n)
			print_link(leaf, level+1);
	}
}

}

void py_bind_tree(py::module& m) {
	py::class_<inode>(m, "inode")
		.def(py::init<std::string, std::string>())
		.def_readonly("owner", &inode::owner)
		.def_readonly("group", &inode::group)
		.def_property_readonly("suid", [](const inode& i) { return i.suid; })
		.def_property_readonly("sgid", [](const inode& i) { return i.sgid; })
		.def_property_readonly("sticky", [](const inode& i) { return i.sticky; })
		.def_property_readonly("u", [](const inode& i) { return i.u; })
		.def_property_readonly("g", [](const inode& i) { return i.g; })
		.def_property_readonly("o", [](const inode& i) { return i.o; })
	;

	py::class_<link, py_link<>, std::shared_ptr<link>> link_pyface(m, "link");
	link_pyface
		.def(py::init<std::string>())
		.def("clone", &link::clone)
		.def("data", &link::data)
		.def("type_id", &link::type_id)
		.def("oid", &link::oid)
		.def("obj_type_id", &link::obj_type_id)
		.def("data_node", &link::data_node)
		.def_property_readonly("id", [](const link& L) {
			return boost::uuids::to_string(L.id());
		})
		.def_property_readonly("name", &link::name)
		.def_property("inode",
			py::overload_cast<>(&link::get_inode, py::const_),
			py::overload_cast<>(&link::get_inode)
		)
		.def_property_readonly("owner", &link::owner)
	;

	py::class_<hard_link, link, py_link<hard_link>, std::shared_ptr<hard_link>>(m, "hard_link")
		.def(py::init<std::string, sp_obj>())
	;
	py::class_<weak_link, link, py_link<weak_link>, std::shared_ptr<weak_link>>(m, "weak_link")
		.def(py::init<std::string, const sp_obj&>())
	;

	// forward define node
	py::class_<node, objbase, std::shared_ptr<node>> node_pyface(m, "node");

	// export node's Key enum
	py::enum_<node::Key>(node_pyface, "Key")
		.value("ID", node::Key::ID)
		.value("OID", node::Key::OID)
		.value("Name", node::Key::Name)
		.value("Type", node::Key::Type)
		.value("AnyOrder", node::Key::AnyOrder)
	;
	// export node's insert policy
	py::enum_<node::InsertPolicy>(node_pyface, "InsertPolicy")
		.value("AllowDupNames", node::InsertPolicy::AllowDupNames)
		.value("DenyDupNames", node::InsertPolicy::DenyDupNames)
		.value("RenameDup", node::InsertPolicy::RenameDup)
		.value("DenyDupOID", node::InsertPolicy::DenyDupOID)
		.value("Merge", node::InsertPolicy::Merge)
		.export_values();
	;

	// fill node with methods
	node_pyface
		BSPY_EXPORT_DEF(node)
		.def(py::init<>())
		.def("__len__", &node::size)
		.def("__iter__",
			[](const node& N) { return py::make_iterator(N.begin(), N.end()); },
			py::keep_alive<0, 1>()
		)

		// check by link ID or object object's ID
		.def("__contains__", [](const node& N, py::object key) {
			if(PyString_Check(key.ptr()))
				return N.find(uuid_from_str(py::cast<std::string>(key))) != N.end<>();
			return N.find_oid(py::cast<sp_obj>(key)->id()) != N.end<>();
		})
		// check by link name
		.def("contains_name", [](const node& N, const std::string& lname) {
			return N.find(lname) != N.end<>();
		}, "link_name", "Check if node contains link with given name")
		// check by object ID
		.def("contains_oid", [](const node& N, const std::string& oid) {
			return N.find_oid(oid) != N.end<>();
		}, "oid", "Check if node contains link to object with given ID")
		// check by object type
		.def("contains_type", [](const node& N, const std::string& type_id) {
			return N.equal_type(type_id).first != N.end<node::Key::Type>();
		}, "obj_type_id", "Check if node contain links to objects with given type")

		// get item by int index
		.def("__getitem__", [](const node& N, const long idx) {
			// support for Pythonish indexing from both ends
			if(std::size_t(std::abs(idx)) > N.size())
				throw py::key_error("Index out of bounds");
			auto pos = idx < 0 ? N.end() : N.begin();
			std::advance(pos, idx);
			if(pos == N.end()) throw py::key_error("Index out of bounds");
			return *pos;
		}, "link_idx"_a)
		// search by link name
		.def("__getitem__", [](const node& N, const std::string& lid) {
			auto r = N.find(uuid_from_str(lid));
			if(r != N.end<>()) return *r;
			throw py::key_error("Node doesn't contain link with ID " + lid);
		}, "link_name"_a)
		// search by object instance
		.def("__getitem__", [](const node& N, const sp_obj& obj) {
			auto r = N.find(obj->id());
			if(r != N.end<>()) return *r;
			throw py::key_error("Node doesn't contain links to object with ID = " + obj->id());
		}, "object"_a)
		// search by object ID
		.def("find_oid", [](const node& N, const std::string& oid) {
			auto r = N.find_oid(oid);
			if(r != N.end<>()) return *r;
			throw py::key_error("Node doesn't contain links to object with ID - " + oid);
		}, "oid"_a, "Find link by object ID")
		// search by link name
		.def("find_name", [](const node& N, const std::string& lname) {
			auto r = N.find(lname);
			if(r != N.end<>()) return *r;
			throw py::key_error("Node doesn't contain link with name '" + lname + "'");
		}, "link_name"_a, "Find link by name")

		// obtain index in custom order from link
		.def("index", [](const node& N, const std::string& lid) {
			return N.index(uuid_from_str(lid));
		}, "lid"_a, "Find index of link with given ID")
		.def("index", [](const node& N, const sp_link& l) {
			return N.index(l->id());
		}, "link"_a, "Find index of given link")

		// deep search by link ID or object ID
		.def("deep_search", [](const node& N, py::object key) {
			if(PyString_Check(key.ptr()))
				return N.deep_search(uuid_from_str(py::cast<std::string>(key)));
			return N.deep_search_oid(py::cast<sp_obj>(key)->id());
		}, "key"_a, "Deep search for link with given ID or by object instance (OID)")
		.def("deep_search_name", [](const node& N, const std::string& lname) {
			return N.deep_search(lname);
		}, "link_name"_a, "Deep search for link with given name")
		// deep search by object ID
		.def("deep_search_oid", [](const node& N, const std::string& oid) {
			return N.deep_search_oid(oid);
		}, "oid"_a, "Deep search for link to object with given ID")

		.def("equal_range", [](const node& N, const std::string& link_name) {
			auto r = N.equal_range(link_name);
			return py::make_iterator(r.first, r.second);
		}, py::keep_alive<0, 1>(), "link_name"_a)
		.def("equal_range_oid", [](const node& N, const std::string& oid) {
			auto r = N.equal_range_oid(oid);
			return py::make_iterator(r.first, r.second);
		}, py::keep_alive<0, 1>(), "OID"_a)
		.def("equal_type", [](const node& N, const std::string& type_id) {
			auto r = N.equal_type(type_id);
			return py::make_iterator(r.first, r.second);
		}, py::keep_alive<0, 1>(), "obj_type_id"_a)

		// insert given link
		.def("insert", [](node& N, sp_link l, uint pol = node::AllowDupNames) {
			return N.insert(std::move(l)).second;
		}, "link"_a, "pol"_a = node::AllowDupNames, "Insert given link")
		// insert hard link to given object
		.def("insert", [](node& N, std::string name, sp_obj obj, uint pol = node::AllowDupNames) {
			return N.insert(std::move(name), std::move(obj), pol).second;
		}, "name"_a, "obj"_a, "pol"_a = node::AllowDupNames, "Insert hard link to given object")

		// erase by given index
		.def("__delitem__", [](node& N, const long idx) {
			// support for Pythonish indexing from both ends
			if(std::size_t(std::abs(idx)) > N.size())
				throw py::key_error("Index out of bounds");
			N.erase(idx < 0 ? N.size() + idx : idx);
		})
		// erase by given link ID or object instance (object's ID)
		.def("__delitem__", [](node& N, py::object key) {
			if(PyString_Check(key.ptr()))
				N.erase(uuid_from_str(py::cast<std::string>(key)));
			else
				N.erase_oid(py::cast<sp_obj>(key)->id());
		})
		.def("erase", [](node& N, const std::string& key) {
			N.erase(uuid_from_str(key));
		}, "lid"_a, "Erase link with given ID")
		.def("erase_name", (void (node::*)(const std::string&))&node::erase,
			"link_name"_a, "Erase links with given name")
		.def("erase_oid", &node::erase_oid, "obj"_a, "Erase links to given object")
		.def("erase_type", [](node& N, const std::string& type_id) {
			N.erase_type(type_id);
		}, "obj_type_id"_a, "Erase all links pointing to objects with given type")

		// misc functions
		.def_property_readonly("size", &node::size)
		.def_property_readonly("empty", &node::empty)
		.def("clear", &node::clear, "Clears all node contents")
		.def("keys", [](const node& N, node::Key ktype = node::Key::Name) {
			if(ktype == node::Key::ID) {
				// convert UUIDs to string representation
				auto keys = N.keys<>();
				std::vector<std::string> res;
				res.reserve(keys.size());
				for(const auto& k : keys)
					res.emplace_back(boost::uuids::to_string(k));
				return res;
			}
			else {
				switch(ktype) {
				default:
				case node::Key::Name :
					return N.keys<node::Key::Name>();
				case node::Key::OID :
					return N.keys<node::Key::OID>();
				case node::Key::Type :
					return N.keys<node::Key::Type>();
				};
			}
		}, "key_type"_a = node::Key::Name)
	;

	m.def("print_link", [](const sp_link& l) { print_link(l, 0); });
	m.def("print_link", [](const sp_node& n, std::string name = "/") {
		print_link(std::make_shared<tree::hard_link>(name, n), 0);
	}, "node"_a, "root_name"_a = "/");
}

NAMESPACE_END(python)
NAMESPACE_END(blue_sky)

<|endoftext|>


<commit_before>// Begin CVS Header
//   $Source: /Volumes/Home/Users/shoops/cvs/copasi_dev/copasi/UI/CQMathMatrixWidget.cpp,v $
//   $Revision: 1.1 $
//   $Name:  $
//   $Author: ssahle $
//   $Date: 2007/02/09 16:49:41 $
// End CVS Header

// Copyright (C) 2007 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc. and EML Research, gGmbH.
// All rights reserved.

//#include <qpushbutton.h>
#include <qlayout.h>
#include <qlineedit.h>
#include <qlabel.h>
#include <qtable.h>

#include "copasi.h"

#include "CQMathMatrixWidget.h"
#include "qtUtilities.h"
//#include "sensitivities/CSensTask.h"
//#include "sensitivities/CSensProblem.h"

#include "CopasiDataModel/CCopasiDataModel.h"
//#include "utilities/CCopasiVector.h"

#include "model/CModel.h"

#include <qtabwidget.h>

/**
 *  Constructs a CQMathMatrixWidget which is a child of 'parent', with the
 *  name 'name' and widget flags set to 'f'.
 */
CQMathMatrixWidget::CQMathMatrixWidget(QWidget* parent, const char* name, WFlags fl)
    : CopasiWidget(parent, name, fl)
{
  if (!name)
    setName("CQMathMatrixWidget");
  setCaption("CQMathMatrixWidget");

  mWidgetLayout = new QGridLayout(this, 1, 1, 11, 6, "CQMathMatrixWidgetLayout");

  // **********  Label **************
  mLabelTitle = new QLabel(this, "SensLabel");
  mLabelTitle->setText("Sensitivities");
  mLabelTitle->setAlignment(int(QLabel::AlignVCenter
                                | QLabel::AlignLeft));
  mLabelTitle->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
  mWidgetLayout->addWidget(mLabelTitle, 0, 0);

  // tab widget
  mpTab = new QTabWidget(this, "TabWidget");
  mWidgetLayout->addMultiCellWidget(mpTab, 1, 2, 0, 2);

  // 1
  mArrayWidget1 = new CQArrayAnnotationsWidget(mpTab, "ArrayWidget1");
  //mArrayWidget1->setColorCoding(new CColorScale1());
  //CColorScaleAverage * tcs = new CColorScaleAverage();
  CColorScaleBiLog * tcs = new CColorScaleBiLog();
  mArrayWidget1->setColorCoding(tcs);
  //tcs->setMinMax(-1,1);
  //tcs->setSymmetric(true);
  //tcs->setFactor(3.0);
  mArrayWidget1->setColorScalingAutomatic(true);
  mpTab->addTab(mArrayWidget1, "Stoichiometry Matrix");

  // 2
  mArrayWidget2 = new CQArrayAnnotationsWidget(mpTab, "ArrayWidget2");
  //mArrayWidge2->setColorCoding(new CColorScale1());
  tcs = new CColorScaleBiLog();
  mArrayWidget2->setColorCoding(tcs);
  //tcs2->setMinMax(-1,1);
  //tcs2->setSymmetric(true);
  //tcs2->setFactor(3.0);
  mArrayWidget2->setColorScalingAutomatic(true);
  mpTab->addTab(mArrayWidget2, "Reduced Stoichiometry Matrix");

  // 3
  mArrayWidget3 = new CQArrayAnnotationsWidget(mpTab, "ArrayWidget3");
  //mArrayWidge2->setColorCoding(new CColorScale1());
  tcs = new CColorScaleBiLog();
  mArrayWidget3->setColorCoding(tcs);
  //tcs2->setMinMax(-1,1);
  //tcs2->setSymmetric(true);
  //tcs2->setFactor(3.0);
  mArrayWidget3->setColorScalingAutomatic(true);
  mpTab->addTab(mArrayWidget3, "Link Matrix");
}

/*
 *  Destroys the object and frees any allocated resources
 */
CQMathMatrixWidget::~CQMathMatrixWidget()
{}

void CQMathMatrixWidget::loadMatrices()
{
  //   CSensTask * pTask =
  //     dynamic_cast<CSensTask*>((*CCopasiDataModel::Global->getTaskList())["Sensitivities"]);
  //   if (!pTask)
  //     {
  //       clearArrays();
  //       return;
  //}
  //
  //   CSensProblem * pProblem = dynamic_cast< CSensProblem * >(pTask->getProblem());
  //   if (!pProblem)
  //     {
  //       clearArrays();
  //       return;
  //}

  const CModel* pModel = CCopasiDataModel::Global->getModel();

  //mpResult = pProblem->getResultAnnotated();
  //mpScaledResult = pProblem->getScaledResultAnnotated();

  const CArrayAnnotation * tmp;

  tmp = dynamic_cast<const CArrayAnnotation *>
        (pModel->getObject(CCopasiObjectName("Array=Stoichiometry(ann)")));
  mArrayWidget1->setArrayAnnotation(tmp);

  tmp = dynamic_cast<const CArrayAnnotation *>
        (pModel->getObject(CCopasiObjectName("Array=Reduced stoichiometry(ann)")));
  mArrayWidget2->setArrayAnnotation(tmp);

  tmp = dynamic_cast<const CArrayAnnotation *>
        (pModel->getObject(CCopasiObjectName("Array=Link matrix(ann)")));
  mArrayWidget3->setArrayAnnotation(tmp);
}

void CQMathMatrixWidget::clearArrays()
{
  mArrayWidget1->setArrayAnnotation(NULL);
  mArrayWidget2->setArrayAnnotation(NULL);
  mArrayWidget3->setArrayAnnotation(NULL);
}

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

bool CQMathMatrixWidget::update(ListViews::ObjectType C_UNUSED(objectType), ListViews::Action
                                C_UNUSED(action), const std::string & C_UNUSED(key))
{
  /*  if (this->isShown())
      return loadFromBackend();
    else
      return true;*/
  return true;
}

bool CQMathMatrixWidget::leave()
{
  return true;
}

bool CQMathMatrixWidget::enter(const std::string & C_UNUSED(key))
{
  //clear the widget if the pointer to the result has changed
  /*  CSensTask * pTask =
      dynamic_cast<CSensTask*>((*CCopasiDataModel::Global->getTaskList())["Sensitivities"]);
    if (!pTask)
      {
        clearArrays();
        return false;
      }

    CSensProblem * pProblem = dynamic_cast< CSensProblem * >(pTask->getProblem());
    if (!pProblem)
      {
        clearArrays();
        return false;
      }

    if (mpResult != pProblem->getResultAnnotated())
      {
        clearArrays();
        return false;
      }
  */
  loadMatrices();

  return true;
}
<commit_msg>improvement in color scaling<commit_after>// Begin CVS Header
//   $Source: /Volumes/Home/Users/shoops/cvs/copasi_dev/copasi/UI/CQMathMatrixWidget.cpp,v $
//   $Revision: 1.2 $
//   $Name:  $
//   $Author: ssahle $
//   $Date: 2007/02/12 00:04:23 $
// End CVS Header

// Copyright (C) 2007 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc. and EML Research, gGmbH.
// All rights reserved.

//#include <qpushbutton.h>
#include <qlayout.h>
#include <qlineedit.h>
#include <qlabel.h>
#include <qtable.h>

#include "copasi.h"

#include "CQMathMatrixWidget.h"
#include "qtUtilities.h"
//#include "sensitivities/CSensTask.h"
//#include "sensitivities/CSensProblem.h"

#include "CopasiDataModel/CCopasiDataModel.h"
//#include "utilities/CCopasiVector.h"

#include "model/CModel.h"

#include <qtabwidget.h>

/**
 *  Constructs a CQMathMatrixWidget which is a child of 'parent', with the
 *  name 'name' and widget flags set to 'f'.
 */
CQMathMatrixWidget::CQMathMatrixWidget(QWidget* parent, const char* name, WFlags fl)
    : CopasiWidget(parent, name, fl)
{
  if (!name)
    setName("CQMathMatrixWidget");
  setCaption("CQMathMatrixWidget");

  mWidgetLayout = new QGridLayout(this, 1, 1, 11, 6, "CQMathMatrixWidgetLayout");

  // **********  Label **************
  mLabelTitle = new QLabel(this, "SensLabel");
  mLabelTitle->setText("Sensitivities");
  mLabelTitle->setAlignment(int(QLabel::AlignVCenter
                                | QLabel::AlignLeft));
  mLabelTitle->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
  mWidgetLayout->addWidget(mLabelTitle, 0, 0);

  // tab widget
  mpTab = new QTabWidget(this, "TabWidget");
  mWidgetLayout->addMultiCellWidget(mpTab, 1, 2, 0, 2);

  // 1
  mArrayWidget1 = new CQArrayAnnotationsWidget(mpTab, "ArrayWidget1");
  //mArrayWidget1->setColorCoding(new CColorScale1());
  //CColorScaleAverage * tcs = new CColorScaleAverage();
  CColorScaleSimple * tcs = new CColorScaleSimple();
  mArrayWidget1->setColorCoding(tcs);
  tcs->setMinMax(-1.5, 1.5);
  //tcs->setMinMax(-1,1);
  //tcs->setSymmetric(true);
  //tcs->setFactor(3.0);
  mArrayWidget1->setColorScalingAutomatic(false);
  mpTab->addTab(mArrayWidget1, "Stoichiometry Matrix");

  // 2
  mArrayWidget2 = new CQArrayAnnotationsWidget(mpTab, "ArrayWidget2");
  //mArrayWidge2->setColorCoding(new CColorScale1());
  tcs = new CColorScaleSimple();
  mArrayWidget2->setColorCoding(tcs);
  tcs->setMinMax(-1.5, 1.5);
  //tcs2->setMinMax(-1,1);
  //tcs2->setSymmetric(true);
  //tcs2->setFactor(3.0);
  mArrayWidget2->setColorScalingAutomatic(false);
  mpTab->addTab(mArrayWidget2, "Reduced Stoichiometry Matrix");

  // 3
  mArrayWidget3 = new CQArrayAnnotationsWidget(mpTab, "ArrayWidget3");
  //mArrayWidge2->setColorCoding(new CColorScale1());
  tcs = new CColorScaleSimple();
  mArrayWidget3->setColorCoding(tcs);
  tcs->setMinMax(-1.5, 1.5);
  //tcs2->setMinMax(-1,1);
  //tcs2->setSymmetric(true);
  //tcs2->setFactor(3.0);
  mArrayWidget3->setColorScalingAutomatic(false);
  mpTab->addTab(mArrayWidget3, "Link Matrix");
}

/*
 *  Destroys the object and frees any allocated resources
 */
CQMathMatrixWidget::~CQMathMatrixWidget()
{}

void CQMathMatrixWidget::loadMatrices()
{
  //   CSensTask * pTask =
  //     dynamic_cast<CSensTask*>((*CCopasiDataModel::Global->getTaskList())["Sensitivities"]);
  //   if (!pTask)
  //     {
  //       clearArrays();
  //       return;
  //}
  //
  //   CSensProblem * pProblem = dynamic_cast< CSensProblem * >(pTask->getProblem());
  //   if (!pProblem)
  //     {
  //       clearArrays();
  //       return;
  //}

  const CModel* pModel = CCopasiDataModel::Global->getModel();

  //mpResult = pProblem->getResultAnnotated();
  //mpScaledResult = pProblem->getScaledResultAnnotated();

  const CArrayAnnotation * tmp;

  tmp = dynamic_cast<const CArrayAnnotation *>
        (pModel->getObject(CCopasiObjectName("Array=Stoichiometry(ann)")));
  mArrayWidget1->setArrayAnnotation(tmp);

  tmp = dynamic_cast<const CArrayAnnotation *>
        (pModel->getObject(CCopasiObjectName("Array=Reduced stoichiometry(ann)")));
  mArrayWidget2->setArrayAnnotation(tmp);

  tmp = dynamic_cast<const CArrayAnnotation *>
        (pModel->getObject(CCopasiObjectName("Array=Link matrix(ann)")));
  mArrayWidget3->setArrayAnnotation(tmp);
}

void CQMathMatrixWidget::clearArrays()
{
  mArrayWidget1->setArrayAnnotation(NULL);
  mArrayWidget2->setArrayAnnotation(NULL);
  mArrayWidget3->setArrayAnnotation(NULL);
}

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

bool CQMathMatrixWidget::update(ListViews::ObjectType C_UNUSED(objectType), ListViews::Action
                                C_UNUSED(action), const std::string & C_UNUSED(key))
{
  /*  if (this->isShown())
      return loadFromBackend();
    else
      return true;*/
  return true;
}

bool CQMathMatrixWidget::leave()
{
  return true;
}

bool CQMathMatrixWidget::enter(const std::string & C_UNUSED(key))
{
  //clear the widget if the pointer to the result has changed
  /*  CSensTask * pTask =
      dynamic_cast<CSensTask*>((*CCopasiDataModel::Global->getTaskList())["Sensitivities"]);
    if (!pTask)
      {
        clearArrays();
        return false;
      }

    CSensProblem * pProblem = dynamic_cast< CSensProblem * >(pTask->getProblem());
    if (!pProblem)
      {
        clearArrays();
        return false;
      }

    if (mpResult != pProblem->getResultAnnotated())
      {
        clearArrays();
        return false;
      }
  */
  loadMatrices();

  return true;
}
<|endoftext|>


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

#include <gtest/gtest.h>

#include "./intern.h"

#include <climits>
#include <fstream>
#include <string>
#include <algorithm>

#include "./serialization.h"

using namespace std;
using namespace jubatus::util::data;
using namespace jubatus::util::data::serialization;

static const char* tmp_file="./tmp";

TEST(intern_test, string) {
  srandom(time(NULL));
  intern<string> im;

  // make a random string set
  vector<string> ss;
  for (int i=0;i<1000;++i) {
    string s;
    for (int j=0;j<32;++j) s+=random()%26+'a';
    ss.push_back(s);
  }
  sort(ss.begin(),ss.end());
  ss.erase(unique(ss.begin(),ss.end()),ss.end());

  for (size_t i=0;i<ss.size();++i) EXPECT_EQ(-1,im.key2id(ss[i],false));
  for (size_t i=0;i<ss.size();++i) EXPECT_EQ(int(i),im.key2id(ss[i],true));
  for (size_t i=0;i<ss.size();++i) EXPECT_EQ(ss[i],im.id2key(i));
}

TEST(intern_test, count) {
  intern<string> im;
  string hoge="hoge";
  EXPECT_FALSE(im.exist_key(hoge));
  EXPECT_FALSE(im.exist_id(0));
  im.key2id(hoge);
  EXPECT_TRUE(im.exist_key(hoge));
  EXPECT_TRUE(im.exist_id(0));
}

TEST(intern_test, serialize) {
  srandom(time(NULL));
  // make a random string set
  vector<string> ss;
  for (int i=0;i<1000;++i) {
    string s;
    for (int j=0;j<32;++j) s+=random()%26+'a';
    ss.push_back(s);
  }
  sort(ss.begin(),ss.end());
  ss.erase(unique(ss.begin(),ss.end()),ss.end());

  {
    // serialize
    intern<string> im;
    for (size_t i=0;i<ss.size();++i) im.key2id(ss[i]);
    ofstream ofs(tmp_file);
    binary_oarchive oa(ofs);
    oa<<im;
  }

  {
    // deserialize
    intern<string> im;
    ifstream ifs(tmp_file);
    binary_iarchive ia(ifs);
    ia>>im;
    EXPECT_EQ(ss.size(),im.size());
    for (size_t i=0;i<ss.size();++i) EXPECT_EQ(int(i),im.key2id(ss[i],false));
    for (size_t i=0;i<ss.size();++i) EXPECT_EQ(ss[i],im.id2key(i));

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

#include <gtest/gtest.h>

#include "./intern.h"

#include <climits>
#include <sstream>
#include <string>
#include <algorithm>

#include "./serialization.h"

using namespace std;
using namespace jubatus::util::data;
using namespace jubatus::util::data::serialization;

TEST(intern_test, string) {
  srandom(time(NULL));
  intern<string> im;

  // make a random string set
  vector<string> ss;
  for (int i=0;i<1000;++i) {
    string s;
    for (int j=0;j<32;++j) s+=random()%26+'a';
    ss.push_back(s);
  }
  sort(ss.begin(),ss.end());
  ss.erase(unique(ss.begin(),ss.end()),ss.end());

  for (size_t i=0;i<ss.size();++i) EXPECT_EQ(-1,im.key2id(ss[i],false));
  for (size_t i=0;i<ss.size();++i) EXPECT_EQ(int(i),im.key2id(ss[i],true));
  for (size_t i=0;i<ss.size();++i) EXPECT_EQ(ss[i],im.id2key(i));
}

TEST(intern_test, count) {
  intern<string> im;
  string hoge="hoge";
  EXPECT_FALSE(im.exist_key(hoge));
  EXPECT_FALSE(im.exist_id(0));
  im.key2id(hoge);
  EXPECT_TRUE(im.exist_key(hoge));
  EXPECT_TRUE(im.exist_id(0));
}

TEST(intern_test, serialize) {
  srandom(time(NULL));
  // make a random string set
  vector<string> ss;
  for (int i=0;i<1000;++i) {
    string s;
    for (int j=0;j<32;++j) s+=random()%26+'a';
    ss.push_back(s);
  }
  sort(ss.begin(),ss.end());
  ss.erase(unique(ss.begin(),ss.end()),ss.end());

  stringstream stream;

  {
    // serialize
    intern<string> im;
    for (size_t i=0;i<ss.size();++i) im.key2id(ss[i]);
    binary_oarchive oa(stream);
    oa<<im;
  }

  {
    // deserialize
    intern<string> im;
    binary_iarchive ia(stream);
    ia>>im;
    EXPECT_EQ(ss.size(),im.size());
    for (size_t i=0;i<ss.size();++i) EXPECT_EQ(int(i),im.key2id(ss[i],false));
    for (size_t i=0;i<ss.size();++i) EXPECT_EQ(ss[i],im.id2key(i));

  }
}
<|endoftext|>


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

Copyright (c) 2016, Daniel Walz
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
   list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

3. Neither the name of the copyright holder nor the names of its contributors
   may be used to endorse or promote products derived from this software without
   specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
OF THE POSSIBILITY OF SUCH DAMAGE.

  ==============================================================================

    juce_ak_layout.cpp
    Created: 21 Feb 2016 9:14:52pm

  ==============================================================================
*/

#include "juce_ak_layout.h"

Layout::Layout(Orientation o, juce::Component* owner)
  : orientation (o),
    isUpdating (false),
    isCummulatingStretch (false),
    owningComponent (owner)
{
}

Layout::~Layout()
{
}

void Layout::setOrientation (const Orientation o)
{
    orientation = o;
}

LayoutItem* Layout::addComponent (juce::Component* c, int idx)
{
    LayoutItem* item = itemsList.insert (idx, new LayoutItem (c));
    updateGeometry();
    return item;
}

void Layout::removeComponent (juce::Component* c)
{
    for (int i=0; i<itemsList.size(); ++i) {
        LayoutItem* item = itemsList.getUnchecked (i);
        if (item->isComponentItem() && item->getComponent() == c) {
            itemsList.remove (i);
        }
    }
    updateGeometry();
}

LayoutItem* Layout::addLabeledComponent (juce::Component* c, Orientation o, juce::Label** labelPtr, int idx)
{
    // if the layout is not owned by a component, the label will not show up,
    // because addAndMakeVisible can not be called.
    jassert (owningComponent);

    juce::Label* label = new juce::Label();
    if (owningComponent) {
        owningComponent->addAndMakeVisible (label);
    }
    float h = label->getFont().getHeight();
    Layout* sub = addSubLayout (o, idx, owningComponent);
    sub->addComponent (label)->setFixedHeight (h);
    LabeledLayoutItem* labeledItem = new LabeledLayoutItem (c, label);
    sub->addRawItem (labeledItem);

    if (labelPtr) {
        *labelPtr = label;
    }

    updateGeometry();
    return labeledItem;
}

LayoutItem* Layout::addLabeledComponent (juce::Component* component, juce::StringRef text, Orientation o, int idx)
{
    LayoutItem* item = addLabeledComponent(component, o, nullptr, idx);
    if (juce::Label* label = item->getLabel()) {
        label->setText (text, juce::dontSendNotification);
        label->setJustificationType (juce::Justification::centred);
    }
    return item;
}

Layout* Layout::addSubLayout (Orientation o, int idx, juce::Component* owner)
{
    SubLayout* sub = new SubLayout (o, owningComponent);
    itemsList.insert (idx, sub);
    updateGeometry();
    return sub;
}

LayoutItem* Layout::addSSpacer (float sx, float sy, int idx)
{
    LayoutItem* item = itemsList.insert (idx, new LayoutItem (LayoutItem::SpacerItem));
    updateGeometry();
    return item;
}

LayoutItem* Layout::getLayoutItem (juce::Component* c)
{
    for (int i=0; i<itemsList.size(); ++i) {
        LayoutItem* item = itemsList.getUnchecked (i);
        if (item->isComponentItem() && item->getComponent() == c) {
            return item;
        }
        else if (item->isSubLayout()) {
            // search also sub layouts recoursively
            if (LayoutItem* subItem = getLayoutItem (c)) {
                return subItem;
            }
        }
    }
    return nullptr;
}

void Layout::addRawItem (LayoutItem* item, int idx)
{
    itemsList.insert (idx, item);
}

void Layout::updateGeometry ()
{
    if (owningComponent) {
        updateGeometry (owningComponent->getLocalBounds());
    }
}

void Layout::updateGeometry (juce::Rectangle<int> bounds)
{
    // recursion check
    if (isUpdating) {
        return;
    }
    isUpdating = true;

    // remove items of deleted or invalid components
    for (int i=0; i<itemsList.size(); ++i) {
        LayoutItem* item = itemsList.getUnchecked (i);
        if (!item->isValid()) {
            itemsList.remove (i);
        }
    }

    itemsBounds.resize (itemsList.size ());

    float cummulatedX, cummulatedY;
    getCummulatedStretch (cummulatedX, cummulatedY);
    float availableWidth  = bounds.getWidth();
    float availableHeight = bounds.getHeight();

    if (orientation == TopDown || orientation == BottomUp) {
        for (int i=0; i<itemsList.size(); ++i) {
            LayoutItem* item = itemsList.getUnchecked (i);
            float sx, sy;
            item->getStretch (sx, sy);
            float h = bounds.getHeight() * sy / cummulatedY;
            juce::Rectangle<int> childBounds (bounds.getX(), bounds.getY(), bounds.getWidth(), h);
            bool changedWidth, changedHeight;
            item->constrainBounds (childBounds, changedWidth, changedHeight);
            itemsBounds.set (i, childBounds);
            if (changedHeight) {
                itemBoundsFinal.set (i, true);
                availableHeight -= childBounds.getHeight();
                cummulatedY -= sy;
            }
            else {
                itemBoundsFinal.set (i, false);
            }
            if (changedWidth) {
                availableWidth = std::max (bounds.getWidth(), childBounds.getWidth());
            }
        }

        float y = bounds.getY();
        if (orientation == BottomUp) {
            y = bounds.getY() + bounds.getHeight();
        }
        for (int i=0; i<itemsList.size(); ++i) {
            LayoutItem* item = itemsList.getUnchecked (i);

            if (itemBoundsFinal.getUnchecked (i)) {
                float h = itemsBounds.getReference (i).getHeight();
                if (orientation == BottomUp) {
                    y -= h;
                }
                juce::Rectangle<int> childBounds (bounds.getX(), y, availableWidth, h);
                if (item->isSubLayout()) {
                    if (Layout* sub = dynamic_cast<Layout*>(item)) {
                        sub->updateGeometry (item->getPaddedBounds (childBounds));
                    }
                }
                if (juce::Component* c = item->getComponent()) {
                    c->setBounds (item->getPaddedBounds (childBounds));
                }

                if (orientation == TopDown) {
                    y += h;
                }
            }
            else {
                float sx, sy;
                item->getStretch (sx, sy);
                float h = availableHeight * sy /cummulatedY;
                if (orientation == BottomUp) {
                    y -= h;
                }
                juce::Rectangle<int> childBounds (bounds.getX(), y, availableWidth, h );
                if (item->isSubLayout()) {
                    if (Layout* sub = dynamic_cast<Layout*>(item)) {
                        sub->updateGeometry (item->getPaddedBounds (childBounds));
                    }
                }
                if (juce::Component* c = item->getComponent()) {
                    c->setBounds (item->getPaddedBounds (childBounds));
                }
                if (orientation == TopDown) {
                    y += h;
                }
            }
        }
    } else if (orientation == LeftToRight || orientation == RightToLeft) {
        for (int i=0; i<itemsList.size(); ++i) {
            LayoutItem* item = itemsList.getUnchecked (i);
            float sx, sy;
            item->getStretch (sx, sy);
            float w = bounds.getWidth() * sx / cummulatedX;
            juce::Rectangle<int> childBounds (bounds.getX(), bounds.getY(), w, bounds.getHeight());
            bool changedWidth, changedHeight;
            item->constrainBounds (childBounds, changedWidth, changedHeight);
            itemsBounds.set (i, childBounds);
            if (changedWidth) {
                itemBoundsFinal.set (i, true);
                availableWidth -= childBounds.getWidth();
                cummulatedX -= sx;
            }
            else {
                itemBoundsFinal.set (i, false);
            }
            if (changedHeight) {
                availableHeight = std::max (bounds.getHeight(), childBounds.getHeight());
            }
        }

        float x = bounds.getX();
        if (orientation == RightToLeft) {
            x = bounds.getX() + bounds.getWidth();
        }
        for (int i=0; i<itemsList.size(); ++i) {
            LayoutItem* item = itemsList.getUnchecked (i);

            if (itemBoundsFinal.getUnchecked (i)) {
                float w = itemsBounds.getReference (i).getWidth();
                if (orientation == RightToLeft) {
                    x -= w;
                }
                juce::Rectangle<int> childBounds (x, bounds.getY(), w, availableHeight);
                if (item->isSubLayout()) {
                    if (Layout* sub = dynamic_cast<Layout*>(item)) {
                        sub->updateGeometry (item->getPaddedBounds (childBounds));
                    }
                }
                if (juce::Component* c = item->getComponent()) {
                    c->setBounds (item->getPaddedBounds (childBounds));
                }

                if (orientation == LeftToRight) {
                    x += w;
                }
            }
            else {
                float sx, sy;
                item->getStretch (sx, sy);
                float w = availableWidth * sx /cummulatedX;
                if (orientation == RightToLeft) {
                    x -= w;
                }
                juce::Rectangle<int> childBounds (x, bounds.getY(), w, availableHeight);
                if (item->isSubLayout()) {
                    if (Layout* sub = dynamic_cast<Layout*>(item)) {
                        sub->updateGeometry (item->getPaddedBounds (childBounds));
                    }
                }
                if (juce::Component* c = item->getComponent()) {
                    c->setBounds (item->getPaddedBounds (childBounds));
                }
                if (orientation == LeftToRight) {
                    x += w;
                }
            }
        }
    }

    isUpdating = false;
}

void Layout::getCummulatedStretch (float& w, float& h) const
{
    w = 0.0;
    h = 0.0;

    if (isCummulatingStretch) {
        return;
    }
    isCummulatingStretch = true;

    for (int i=0; i<itemsList.size(); ++i) {
        LayoutItem* item = itemsList.getUnchecked (i);
        float x, y;
        item->getStretch (x, y);
        if (orientation == LeftToRight || orientation == RightToLeft) {
            w += x;
            h = std::max (h, y);
        }
        else if (orientation == TopDown || orientation == BottomUp) {
            w = std::max (w, x);
            h += y;
        }
        else {
            w += x;
            h += y;
        }
        ++item;
    }

    isCummulatingStretch = false;
}

// =============================================================================
SubLayout::SubLayout (Orientation o, juce::Component* owner) : Layout (o, owner), LayoutItem (LayoutItem::SubLayout)
{

}

void SubLayout::getStretch (float& w, float& h) const
{
    w = 0.0;
    h = 0.0;
    getCummulatedStretch (w, h);
}

<commit_msg>Fixed missing stretch for spacer<commit_after>/*
  ==============================================================================

Copyright (c) 2016, Daniel Walz
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
   list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

3. Neither the name of the copyright holder nor the names of its contributors
   may be used to endorse or promote products derived from this software without
   specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
OF THE POSSIBILITY OF SUCH DAMAGE.

  ==============================================================================

    juce_ak_layout.cpp
    Created: 21 Feb 2016 9:14:52pm

  ==============================================================================
*/

#include "juce_ak_layout.h"

Layout::Layout(Orientation o, juce::Component* owner)
  : orientation (o),
    isUpdating (false),
    isCummulatingStretch (false),
    owningComponent (owner)
{
}

Layout::~Layout()
{
}

void Layout::setOrientation (const Orientation o)
{
    orientation = o;
}

LayoutItem* Layout::addComponent (juce::Component* c, int idx)
{
    LayoutItem* item = itemsList.insert (idx, new LayoutItem (c));
    updateGeometry();
    return item;
}

void Layout::removeComponent (juce::Component* c)
{
    for (int i=0; i<itemsList.size(); ++i) {
        LayoutItem* item = itemsList.getUnchecked (i);
        if (item->isComponentItem() && item->getComponent() == c) {
            itemsList.remove (i);
        }
    }
    updateGeometry();
}

LayoutItem* Layout::addLabeledComponent (juce::Component* c, Orientation o, juce::Label** labelPtr, int idx)
{
    // if the layout is not owned by a component, the label will not show up,
    // because addAndMakeVisible can not be called.
    jassert (owningComponent);

    juce::Label* label = new juce::Label();
    if (owningComponent) {
        owningComponent->addAndMakeVisible (label);
    }
    float h = label->getFont().getHeight();
    Layout* sub = addSubLayout (o, idx, owningComponent);
    sub->addComponent (label)->setFixedHeight (h);
    LabeledLayoutItem* labeledItem = new LabeledLayoutItem (c, label);
    sub->addRawItem (labeledItem);

    if (labelPtr) {
        *labelPtr = label;
    }

    updateGeometry();
    return labeledItem;
}

LayoutItem* Layout::addLabeledComponent (juce::Component* component, juce::StringRef text, Orientation o, int idx)
{
    LayoutItem* item = addLabeledComponent(component, o, nullptr, idx);
    if (juce::Label* label = item->getLabel()) {
        label->setText (text, juce::dontSendNotification);
        label->setJustificationType (juce::Justification::centred);
    }
    return item;
}

Layout* Layout::addSubLayout (Orientation o, int idx, juce::Component* owner)
{
    SubLayout* sub = new SubLayout (o, owningComponent);
    itemsList.insert (idx, sub);
    updateGeometry();
    return sub;
}

LayoutItem* Layout::addSSpacer (float sx, float sy, int idx)
{
    LayoutItem* item = itemsList.insert (idx, new LayoutItem (LayoutItem::SpacerItem));
    item->setStretch (sx, sy);
    updateGeometry();
    return item;
}

LayoutItem* Layout::getLayoutItem (juce::Component* c)
{
    for (int i=0; i<itemsList.size(); ++i) {
        LayoutItem* item = itemsList.getUnchecked (i);
        if (item->isComponentItem() && item->getComponent() == c) {
            return item;
        }
        else if (item->isSubLayout()) {
            // search also sub layouts recoursively
            if (LayoutItem* subItem = getLayoutItem (c)) {
                return subItem;
            }
        }
    }
    return nullptr;
}

void Layout::addRawItem (LayoutItem* item, int idx)
{
    itemsList.insert (idx, item);
}

void Layout::updateGeometry ()
{
    if (owningComponent) {
        updateGeometry (owningComponent->getLocalBounds());
    }
}

void Layout::updateGeometry (juce::Rectangle<int> bounds)
{
    // recursion check
    if (isUpdating) {
        return;
    }
    isUpdating = true;

    // remove items of deleted or invalid components
    for (int i=0; i<itemsList.size(); ++i) {
        LayoutItem* item = itemsList.getUnchecked (i);
        if (!item->isValid()) {
            itemsList.remove (i);
        }
    }

    itemsBounds.resize (itemsList.size ());

    float cummulatedX, cummulatedY;
    getCummulatedStretch (cummulatedX, cummulatedY);
    float availableWidth  = bounds.getWidth();
    float availableHeight = bounds.getHeight();

    if (orientation == TopDown || orientation == BottomUp) {
        for (int i=0; i<itemsList.size(); ++i) {
            LayoutItem* item = itemsList.getUnchecked (i);
            float sx, sy;
            item->getStretch (sx, sy);
            float h = bounds.getHeight() * sy / cummulatedY;
            juce::Rectangle<int> childBounds (bounds.getX(), bounds.getY(), bounds.getWidth(), h);
            bool changedWidth, changedHeight;
            item->constrainBounds (childBounds, changedWidth, changedHeight);
            itemsBounds.set (i, childBounds);
            if (changedHeight) {
                itemBoundsFinal.set (i, true);
                availableHeight -= childBounds.getHeight();
                cummulatedY -= sy;
            }
            else {
                itemBoundsFinal.set (i, false);
            }
            if (changedWidth) {
                availableWidth = std::max (bounds.getWidth(), childBounds.getWidth());
            }
        }

        float y = bounds.getY();
        if (orientation == BottomUp) {
            y = bounds.getY() + bounds.getHeight();
        }
        for (int i=0; i<itemsList.size(); ++i) {
            LayoutItem* item = itemsList.getUnchecked (i);

            if (itemBoundsFinal.getUnchecked (i)) {
                float h = itemsBounds.getReference (i).getHeight();
                if (orientation == BottomUp) {
                    y -= h;
                }
                juce::Rectangle<int> childBounds (bounds.getX(), y, availableWidth, h);
                if (item->isSubLayout()) {
                    if (Layout* sub = dynamic_cast<Layout*>(item)) {
                        sub->updateGeometry (item->getPaddedBounds (childBounds));
                    }
                }
                if (juce::Component* c = item->getComponent()) {
                    c->setBounds (item->getPaddedBounds (childBounds));
                }

                if (orientation == TopDown) {
                    y += h;
                }
            }
            else {
                float sx, sy;
                item->getStretch (sx, sy);
                float h = availableHeight * sy /cummulatedY;
                if (orientation == BottomUp) {
                    y -= h;
                }
                juce::Rectangle<int> childBounds (bounds.getX(), y, availableWidth, h );
                if (item->isSubLayout()) {
                    if (Layout* sub = dynamic_cast<Layout*>(item)) {
                        sub->updateGeometry (item->getPaddedBounds (childBounds));
                    }
                }
                if (juce::Component* c = item->getComponent()) {
                    c->setBounds (item->getPaddedBounds (childBounds));
                }
                if (orientation == TopDown) {
                    y += h;
                }
            }
        }
    } else if (orientation == LeftToRight || orientation == RightToLeft) {
        for (int i=0; i<itemsList.size(); ++i) {
            LayoutItem* item = itemsList.getUnchecked (i);
            float sx, sy;
            item->getStretch (sx, sy);
            float w = bounds.getWidth() * sx / cummulatedX;
            juce::Rectangle<int> childBounds (bounds.getX(), bounds.getY(), w, bounds.getHeight());
            bool changedWidth, changedHeight;
            item->constrainBounds (childBounds, changedWidth, changedHeight);
            itemsBounds.set (i, childBounds);
            if (changedWidth) {
                itemBoundsFinal.set (i, true);
                availableWidth -= childBounds.getWidth();
                cummulatedX -= sx;
            }
            else {
                itemBoundsFinal.set (i, false);
            }
            if (changedHeight) {
                availableHeight = std::max (bounds.getHeight(), childBounds.getHeight());
            }
        }

        float x = bounds.getX();
        if (orientation == RightToLeft) {
            x = bounds.getX() + bounds.getWidth();
        }
        for (int i=0; i<itemsList.size(); ++i) {
            LayoutItem* item = itemsList.getUnchecked (i);

            if (itemBoundsFinal.getUnchecked (i)) {
                float w = itemsBounds.getReference (i).getWidth();
                if (orientation == RightToLeft) {
                    x -= w;
                }
                juce::Rectangle<int> childBounds (x, bounds.getY(), w, availableHeight);
                if (item->isSubLayout()) {
                    if (Layout* sub = dynamic_cast<Layout*>(item)) {
                        sub->updateGeometry (item->getPaddedBounds (childBounds));
                    }
                }
                if (juce::Component* c = item->getComponent()) {
                    c->setBounds (item->getPaddedBounds (childBounds));
                }

                if (orientation == LeftToRight) {
                    x += w;
                }
            }
            else {
                float sx, sy;
                item->getStretch (sx, sy);
                float w = availableWidth * sx /cummulatedX;
                if (orientation == RightToLeft) {
                    x -= w;
                }
                juce::Rectangle<int> childBounds (x, bounds.getY(), w, availableHeight);
                if (item->isSubLayout()) {
                    if (Layout* sub = dynamic_cast<Layout*>(item)) {
                        sub->updateGeometry (item->getPaddedBounds (childBounds));
                    }
                }
                if (juce::Component* c = item->getComponent()) {
                    c->setBounds (item->getPaddedBounds (childBounds));
                }
                if (orientation == LeftToRight) {
                    x += w;
                }
            }
        }
    }

    isUpdating = false;
}

void Layout::getCummulatedStretch (float& w, float& h) const
{
    w = 0.0;
    h = 0.0;

    if (isCummulatingStretch) {
        return;
    }
    isCummulatingStretch = true;

    for (int i=0; i<itemsList.size(); ++i) {
        LayoutItem* item = itemsList.getUnchecked (i);
        float x, y;
        item->getStretch (x, y);
        if (orientation == LeftToRight || orientation == RightToLeft) {
            w += x;
            h = std::max (h, y);
        }
        else if (orientation == TopDown || orientation == BottomUp) {
            w = std::max (w, x);
            h += y;
        }
        else {
            w += x;
            h += y;
        }
        ++item;
    }

    isCummulatingStretch = false;
}

// =============================================================================
SubLayout::SubLayout (Orientation o, juce::Component* owner) : Layout (o, owner), LayoutItem (LayoutItem::SubLayout)
{

}

void SubLayout::getStretch (float& w, float& h) const
{
    w = 0.0;
    h = 0.0;
    getCummulatedStretch (w, h);
}

<|endoftext|>


<commit_before>/******************************************************************************\
* File:          menu.cpp
* Purpose:       Implementation of wxExMenu class
* Author:        Anton van Wezenbeek
* RCS-ID:        $Id$
*
* Copyright (c) 1998-2009 Anton van Wezenbeek
* All rights are reserved. Reproduction in whole or part is prohibited
* without the written consent of the copyright owner.
\******************************************************************************/

#include <wx/wxprec.h>
#ifndef WX_PRECOMP
#include <wx/wx.h>
#endif
#include <map>
#include <wx/extension/menu.h>
#include <wx/extension/art.h>
#include <wx/extension/lexers.h>
#include <wx/extension/tool.h>
#include <wx/extension/util.h> // for wxExEllipsed
#include <wx/extension/vcs.h>

#if wxUSE_GUI

wxExMenu::wxExMenu(long style)
  : m_Style(style)
  , m_MenuVCSFilled(false)
{
}

wxExMenu::wxExMenu(const wxExMenu& menu)
  : m_Style(menu.m_Style)
  , m_MenuVCSFilled(menu.m_MenuVCSFilled)
{
}

wxMenuItem* wxExMenu::Append(int id)
{
  // Using wxMenu::Append(id)
  // also appends the stock item,
  // but does not add the bitmap.

  wxMenuItem* item = new wxMenuItem(this, id);

  const wxExStockArt art(id);

  if (art.GetBitmap().IsOk())
  {
    item->SetBitmap(art.GetBitmap(
      wxART_MENU,
      wxArtProvider::GetSizeHint(wxART_MENU, true)));
  }

  return wxMenu::Append(item);
}

wxMenuItem* wxExMenu::Append(
  int id,
  const wxString& name,
  const wxString& helptext,
  const wxArtID& artid)
{
  wxMenuItem* item = new wxMenuItem(this, id, name, helptext);

  if (!artid.empty())
  {
    const wxBitmap bitmap =
      wxArtProvider::GetBitmap(
        artid,
        wxART_MENU,
        wxArtProvider::GetSizeHint(wxART_MENU, true));

    if (bitmap.IsOk())
    {
      item->SetBitmap(bitmap);
    }
  }

  return wxMenu::Append(item);
}

void wxExMenu::AppendBars()
{
  AppendCheckItem(ID_VIEW_MENUBAR, _("&Menubar"));
  AppendCheckItem(ID_VIEW_STATUSBAR, _("&Statusbar"));
  AppendCheckItem(ID_VIEW_TOOLBAR, _("&Toolbar"));
  AppendCheckItem(ID_VIEW_FINDBAR, _("&Findbar"));
}

void wxExMenu::AppendEdit(bool add_invert)
{
  if (!(m_Style & MENU_IS_READ_ONLY) &&
       (m_Style & MENU_IS_SELECTED))
  {
    Append(wxID_CUT);
  }

  if (m_Style & MENU_IS_SELECTED)
  {
    Append(wxID_COPY);
  }

  if (!(m_Style & MENU_IS_READ_ONLY) &&
       (m_Style & MENU_CAN_PASTE))
  {
    Append(wxID_PASTE);
  }

  if (!(m_Style & MENU_IS_SELECTED) &&
      !(m_Style & MENU_IS_EMPTY))
  {
    Append(wxID_SELECTALL);
  }
  else
  {
    if (add_invert && !(m_Style & MENU_IS_EMPTY))
    {
      Append(ID_EDIT_SELECT_NONE, _("&Deselect All"));
    }
  }

  if (m_Style & MENU_ALLOW_CLEAR)
  {
    Append(wxID_CLEAR);
  }

  if (add_invert && !(m_Style & MENU_IS_EMPTY))
  {
    Append(ID_EDIT_SELECT_INVERT, _("&Invert"));
  }

  if (!(m_Style & MENU_IS_READ_ONLY) &&
       (m_Style & MENU_IS_SELECTED) &&
      !(m_Style & MENU_IS_EMPTY))
  {
    Append(wxID_DELETE);
  }
}

void wxExMenu::AppendPrint()
{
  Append(wxID_PRINT_SETUP, wxExEllipsed(_("Page &Setup")));
  Append(wxID_PREVIEW);
  Append(wxID_PRINT);
}

void wxExMenu::AppendSeparator()
{
  if (
    GetMenuItemCount() == 0 ||
    FindItemByPosition(GetMenuItemCount() - 1)->IsSeparator())
  {
    return;
  }

  wxMenu::AppendSeparator();
}

void wxExMenu::AppendSubMenu(
  wxMenu *submenu,
  const wxString& text,
  const wxString& help,
  int itemid)
{
  if (itemid == wxID_ANY)
  {
    wxMenu::AppendSubMenu(submenu, text, help);
  }
  else
  {
    // This one is deprecated, but is necessary if
    // we have an explicit itemid.
    wxMenu::Append(itemid, text, submenu, help);
  }
}

bool wxExMenu::AppendTools(int itemid)
{
  if (wxExLexers::Get()->Count() == 0)
  {
    return false;
  }

  wxExMenu* menuTool = new wxExMenu(*this);

  for (
    auto it =
      wxExTool::Get()->GetToolInfo().begin();
    it != wxExTool::Get()->GetToolInfo().end();
    ++it)
  {
    if (!it->second.GetText().empty())
    {
      const bool vcs_type = wxExTool(it->first).IsRCSType();

      if ((vcs_type && !wxExVCS::Get()->Use()) || !vcs_type)
      {
        menuTool->Append(
          it->first,
          it->second.GetText(),
          it->second.GetHelpText());
      }
    }
  }

  AppendSubMenu(menuTool, _("&Tools"), wxEmptyString, itemid);

  return true;
}

// This is the VCS submenu, as present on a popup.
// Therefore it is build when clicking, and does not
// need to be destroyed an old one.
void wxExMenu::AppendVCS(const wxExFileName& filename)
{
  if (!wxExVCS::Get()->Use())
  {
    return;
  }

  const int vcs_offset_id = ID_EDIT_VCS_LOWEST + 1;

  wxExMenu* vcsmenu = new wxExMenu;
  wxExVCS::Get()->BuildMenu(vcs_offset_id, vcsmenu, filename);

  if (vcsmenu->GetMenuItemCount() > 0)
  {
    AppendSubMenu(vcsmenu, "&VCS");
  }
}

// This is the general VCS menu, it is in the main menu,
// and because contents depends on actual VCS used,
// it is rebuild after change of VCS system.
void wxExMenu::BuildVCS(bool fill)
{
  if (m_MenuVCSFilled)
  {
    wxMenuItem* item;

    while ((item = FindItem(wxID_SEPARATOR)) != NULL)
    {
      Destroy(item);
    }

    for (int id = ID_VCS_LOWEST + 1; id < ID_VCS_HIGHEST; id++)
    {
      // When using only Destroy, and the item does not exist,
      // an assert happens.
      if (FindItem(id) != NULL)
      {
        Destroy(id);
      }
    }
  }

  if (fill)
  {
    const int vcs_offset_id = ID_VCS_LOWEST + 1;
    wxExVCS::Get()->BuildMenu(vcs_offset_id, this, wxExFileName(), false); // no popup
  }

  m_MenuVCSFilled = fill;
}
#endif // wxUSE_GUI
<commit_msg>fixed return value<commit_after>/******************************************************************************\
* File:          menu.cpp
* Purpose:       Implementation of wxExMenu class
* Author:        Anton van Wezenbeek
* RCS-ID:        $Id$
*
* Copyright (c) 1998-2009 Anton van Wezenbeek
* All rights are reserved. Reproduction in whole or part is prohibited
* without the written consent of the copyright owner.
\******************************************************************************/

#include <wx/wxprec.h>
#ifndef WX_PRECOMP
#include <wx/wx.h>
#endif
#include <map>
#include <wx/extension/menu.h>
#include <wx/extension/art.h>
#include <wx/extension/lexers.h>
#include <wx/extension/tool.h>
#include <wx/extension/util.h> // for wxExEllipsed
#include <wx/extension/vcs.h>

#if wxUSE_GUI

wxExMenu::wxExMenu(long style)
  : m_Style(style)
  , m_MenuVCSFilled(false)
{
}

wxExMenu::wxExMenu(const wxExMenu& menu)
  : m_Style(menu.m_Style)
  , m_MenuVCSFilled(menu.m_MenuVCSFilled)
{
}

wxMenuItem* wxExMenu::Append(int id)
{
  // Using wxMenu::Append(id)
  // also appends the stock item,
  // but does not add the bitmap.

  wxMenuItem* item = new wxMenuItem(this, id);

  const wxExStockArt art(id);

  if (art.GetBitmap().IsOk())
  {
    item->SetBitmap(art.GetBitmap(
      wxART_MENU,
      wxArtProvider::GetSizeHint(wxART_MENU, true)));
  }

  return wxMenu::Append(item);
}

wxMenuItem* wxExMenu::Append(
  int id,
  const wxString& name,
  const wxString& helptext,
  const wxArtID& artid)
{
  wxMenuItem* item = new wxMenuItem(this, id, name, helptext);

  if (!artid.empty())
  {
    const wxBitmap bitmap =
      wxArtProvider::GetBitmap(
        artid,
        wxART_MENU,
        wxArtProvider::GetSizeHint(wxART_MENU, true));

    if (bitmap.IsOk())
    {
      item->SetBitmap(bitmap);
    }
  }

  return wxMenu::Append(item);
}

void wxExMenu::AppendBars()
{
  AppendCheckItem(ID_VIEW_MENUBAR, _("&Menubar"));
  AppendCheckItem(ID_VIEW_STATUSBAR, _("&Statusbar"));
  AppendCheckItem(ID_VIEW_TOOLBAR, _("&Toolbar"));
  AppendCheckItem(ID_VIEW_FINDBAR, _("&Findbar"));
}

void wxExMenu::AppendEdit(bool add_invert)
{
  if (!(m_Style & MENU_IS_READ_ONLY) &&
       (m_Style & MENU_IS_SELECTED))
  {
    Append(wxID_CUT);
  }

  if (m_Style & MENU_IS_SELECTED)
  {
    Append(wxID_COPY);
  }

  if (!(m_Style & MENU_IS_READ_ONLY) &&
       (m_Style & MENU_CAN_PASTE))
  {
    Append(wxID_PASTE);
  }

  if (!(m_Style & MENU_IS_SELECTED) &&
      !(m_Style & MENU_IS_EMPTY))
  {
    Append(wxID_SELECTALL);
  }
  else
  {
    if (add_invert && !(m_Style & MENU_IS_EMPTY))
    {
      Append(ID_EDIT_SELECT_NONE, _("&Deselect All"));
    }
  }

  if (m_Style & MENU_ALLOW_CLEAR)
  {
    Append(wxID_CLEAR);
  }

  if (add_invert && !(m_Style & MENU_IS_EMPTY))
  {
    Append(ID_EDIT_SELECT_INVERT, _("&Invert"));
  }

  if (!(m_Style & MENU_IS_READ_ONLY) &&
       (m_Style & MENU_IS_SELECTED) &&
      !(m_Style & MENU_IS_EMPTY))
  {
    Append(wxID_DELETE);
  }
}

void wxExMenu::AppendPrint()
{
  Append(wxID_PRINT_SETUP, wxExEllipsed(_("Page &Setup")));
  Append(wxID_PREVIEW);
  Append(wxID_PRINT);
}

void wxExMenu::AppendSeparator()
{
  if (
    GetMenuItemCount() == 0 ||
    FindItemByPosition(GetMenuItemCount() - 1)->IsSeparator())
  {
    return;
  }

  wxMenu::AppendSeparator();
}

void wxExMenu::AppendSubMenu(
  wxMenu *submenu,
  const wxString& text,
  const wxString& help,
  int itemid)
{
  if (itemid == wxID_ANY)
  {
    wxMenu::AppendSubMenu(submenu, text, help);
  }
  else
  {
    // This one is deprecated, but is necessary if
    // we have an explicit itemid.
    wxMenu::Append(itemid, text, submenu, help);
  }
}

bool wxExMenu::AppendTools(int itemid)
{
  if (wxExLexers::Get()->Count() == 0)
  {
    return false;
  }

  wxExMenu* menuTool = new wxExMenu(*this);

  for (
    auto it =
      wxExTool::Get()->GetToolInfo().begin();
    it != wxExTool::Get()->GetToolInfo().end();
    ++it)
  {
    if (!it->second.GetText().empty())
    {
      const bool vcs_type = wxExTool(it->first).IsRCSType();

      if ((vcs_type && !wxExVCS::Get()->Use()) || !vcs_type)
      {
        menuTool->Append(
          it->first,
          it->second.GetText(),
          it->second.GetHelpText());
      }
    }
  }

  AppendSubMenu(menuTool, _("&Tools"), wxEmptyString, itemid);

  return true;
}

// This is the VCS submenu, as present on a popup.
// Therefore it is build when clicking, and does not
// need to be destroyed an old one.
void wxExMenu::AppendVCS(const wxExFileName& filename)
{
  if (!wxExVCS::Get()->Use())
  {
    return;
  }

  const int vcs_offset_id = ID_EDIT_VCS_LOWEST + 1;

  wxExMenu* vcsmenu = new wxExMenu;
  wxExVCS::Get()->BuildMenu(vcs_offset_id, vcsmenu, filename);

  if (vcsmenu->GetMenuItemCount() > 0)
  {
    AppendSubMenu(vcsmenu, "&VCS");
  }
}

// This is the general VCS menu, it is in the main menu,
// and because contents depends on actual VCS used,
// it is rebuild after change of VCS system.
void wxExMenu::BuildVCS(bool fill)
{
  if (m_MenuVCSFilled)
  {
    wxMenuItem* item;

    while ((item = FindItem(wxID_SEPARATOR)) != NULL)
    {
      Destroy(item);
    }

    for (int id = ID_VCS_LOWEST + 1; id < ID_VCS_HIGHEST; id++)
    {
      // When using only Destroy, and the item does not exist,
      // an assert happens.
      if (FindItem(id) != NULL)
      {
        Destroy(id);
      }
    }
  }

  if (fill)
  {
    const int vcs_offset_id = ID_VCS_LOWEST + 1;

    wxExVCS::Get()->BuildMenu(
      vcs_offset_id,
      this,
      wxExFileName(),
      false); // no popup

    if (GetMenuItemCount() == 0)
    {
      fill = false;
    }
  }

  m_MenuVCSFilled = fill;
}
#endif // wxUSE_GUI
<|endoftext|>