<commit_before>//===-- GCSE.cpp - SSA based Global Common Subexpr Elimination ------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass is designed to be a very quick global transformation that
// eliminates global common subexpressions from a function.  It does this by
// using an existing value numbering implementation to identify the common
// subexpressions, eliminating them when possible.
//
//===----------------------------------------------------------------------===//

#include "llvm/Transforms/Scalar.h"
#include "llvm/iMemory.h"
#include "llvm/iOther.h"
#include "llvm/Type.h"
#include "llvm/Analysis/Dominators.h"
#include "llvm/Analysis/ValueNumbering.h"
#include "llvm/Support/InstIterator.h"
#include "Support/Statistic.h"
#include "Support/Debug.h"
#include <algorithm>
using namespace llvm;

namespace {
  Statistic<> NumInstRemoved("gcse", "Number of instructions removed");
  Statistic<> NumLoadRemoved("gcse", "Number of loads removed");
  Statistic<> NumCallRemoved("gcse", "Number of calls removed");
  Statistic<> NumNonInsts   ("gcse", "Number of instructions removed due "
                             "to non-instruction values");

  class GCSE : public FunctionPass {
    std::set<Instruction*>  WorkList;
    DominatorSet           *DomSetInfo;
    ValueNumbering         *VN;
  public:
    virtual bool runOnFunction(Function &F);

  private:
    bool EliminateRedundancies(Instruction *I,std::vector<Value*> &EqualValues);
    Instruction *EliminateCSE(Instruction *I, Instruction *Other);
    void ReplaceInstWithInst(Instruction *First, BasicBlock::iterator SI);

    // This transformation requires dominator and immediate dominator info
    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
      AU.setPreservesCFG();
      AU.addRequired<DominatorSet>();
      AU.addRequired<ImmediateDominators>();
      AU.addRequired<ValueNumbering>();
    }
  };

  RegisterOpt<GCSE> X("gcse", "Global Common Subexpression Elimination");
}

// createGCSEPass - The public interface to this file...
FunctionPass *llvm::createGCSEPass() { return new GCSE(); }

// GCSE::runOnFunction - This is the main transformation entry point for a
// function.
//
bool GCSE::runOnFunction(Function &F) {
  bool Changed = false;

  // Get pointers to the analysis results that we will be using...
  DomSetInfo = &getAnalysis<DominatorSet>();
  VN = &getAnalysis<ValueNumbering>();

  // Step #1: Add all instructions in the function to the worklist for
  // processing.  All of the instructions are considered to be our
  // subexpressions to eliminate if possible.
  //
  WorkList.insert(inst_begin(F), inst_end(F));

  // Step #2: WorkList processing.  Iterate through all of the instructions,
  // checking to see if there are any additionally defined subexpressions in the
  // program.  If so, eliminate them!
  //
  while (!WorkList.empty()) {
    Instruction &I = **WorkList.begin(); // Get an instruction from the worklist
    WorkList.erase(WorkList.begin());

    // If this instruction computes a value, try to fold together common
    // instructions that compute it.
    //
    if (I.getType() != Type::VoidTy) {
      std::vector<Value*> EqualValues;
      VN->getEqualNumberNodes(&I, EqualValues);

      if (!EqualValues.empty())
        Changed |= EliminateRedundancies(&I, EqualValues);
    }
  }

  // When the worklist is empty, return whether or not we changed anything...
  return Changed;
}

bool GCSE::EliminateRedundancies(Instruction *I,
                                 std::vector<Value*> &EqualValues) {
  // If the EqualValues set contains any non-instruction values, then we know
  // that all of the instructions can be replaced with the non-instruction value
  // because it is guaranteed to dominate all of the instructions in the
  // function.  We only have to do hard work if all we have are instructions.
  //
  for (unsigned i = 0, e = EqualValues.size(); i != e; ++i)
    if (!isa<Instruction>(EqualValues[i])) {
      // Found a non-instruction.  Replace all instructions with the
      // non-instruction.
      //
      Value *Replacement = EqualValues[i];

      // Make sure we get I as well...
      EqualValues[i] = I;

      // Replace all instructions with the Replacement value.
      for (i = 0; i != e; ++i)
        if (Instruction *I = dyn_cast<Instruction>(EqualValues[i])) {
          // Change all users of I to use Replacement.
          I->replaceAllUsesWith(Replacement);

          if (isa<LoadInst>(I))
            ++NumLoadRemoved; // Keep track of loads eliminated
          if (isa<CallInst>(I))
            ++NumCallRemoved; // Keep track of calls eliminated
          ++NumInstRemoved;   // Keep track of number of instructions eliminated
          ++NumNonInsts;      // Keep track of number of insts repl with values

          // Erase the instruction from the program.
          I->getParent()->getInstList().erase(I);
          WorkList.erase(I);
        }

      return true;
    }

  // Remove duplicate entries from EqualValues...
  std::sort(EqualValues.begin(), EqualValues.end());
  EqualValues.erase(std::unique(EqualValues.begin(), EqualValues.end()),
                    EqualValues.end());

  // From this point on, EqualValues is logically a vector of instructions.
  //
  bool Changed = false;
  EqualValues.push_back(I); // Make sure I is included...
  while (EqualValues.size() > 1) {
    // FIXME, this could be done better than simple iteration!
    Instruction *Test = cast<Instruction>(EqualValues.back());
    EqualValues.pop_back();

    for (unsigned i = 0, e = EqualValues.size(); i != e; ++i)
      if (Instruction *Ret = EliminateCSE(Test,
                                          cast<Instruction>(EqualValues[i]))) {
        if (Ret == Test)          // Eliminated EqualValues[i]
          EqualValues[i] = Test;  // Make sure that we reprocess I at some point
        Changed = true;
        break;
      }
  }
  return Changed;
}

// ReplaceInstWithInst - Destroy the instruction pointed to by SI, making all
// uses of the instruction use First now instead.
//
void GCSE::ReplaceInstWithInst(Instruction *First, BasicBlock::iterator SI) {
  Instruction &Second = *SI;

  DEBUG(std::cerr << "GCSE: Substituting %" << First->getName() << " for: "
                  << Second);

  //cerr << "DEL " << (void*)Second << Second;

  // Add the first instruction back to the worklist
  WorkList.insert(First);

  // Add all uses of the second instruction to the worklist
  for (Value::use_iterator UI = Second.use_begin(), UE = Second.use_end();
       UI != UE; ++UI)
    WorkList.insert(cast<Instruction>(*UI));

  // Make all users of 'Second' now use 'First'
  Second.replaceAllUsesWith(First);

  // Erase the second instruction from the program
  Second.getParent()->getInstList().erase(SI);
}

// EliminateCSE - The two instruction I & Other have been found to be common
// subexpressions.  This function is responsible for eliminating one of them,
// and for fixing the worklist to be correct.  The instruction that is preserved
// is returned from the function if the other is eliminated, otherwise null is
// returned.
//
Instruction *GCSE::EliminateCSE(Instruction *I, Instruction *Other) {
  assert(I != Other);

  WorkList.erase(I);
  WorkList.erase(Other); // Other may not actually be on the worklist anymore...

  // Handle the easy case, where both instructions are in the same basic block
  BasicBlock *BB1 = I->getParent(), *BB2 = Other->getParent();
  Instruction *Ret = 0;

  if (BB1 == BB2) {
    // Eliminate the second occurring instruction.  Add all uses of the second
    // instruction to the worklist.
    //
    // Scan the basic block looking for the "first" instruction
    BasicBlock::iterator BI = BB1->begin();
    while (&*BI != I && &*BI != Other) {
      ++BI;
      assert(BI != BB1->end() && "Instructions not found in parent BB!");
    }

    // Keep track of which instructions occurred first & second
    Instruction *First = BI;
    Instruction *Second = I != First ? I : Other; // Get iterator to second inst
    BI = Second;

    // Destroy Second, using First instead.
    ReplaceInstWithInst(First, BI);
    Ret = First;

    // Otherwise, the two instructions are in different basic blocks.  If one
    // dominates the other instruction, we can simply use it
    //
  } else if (DomSetInfo->dominates(BB1, BB2)) {    // I dom Other?
    ReplaceInstWithInst(I, Other);
    Ret = I;
  } else if (DomSetInfo->dominates(BB2, BB1)) {    // Other dom I?
    ReplaceInstWithInst(Other, I);
    Ret = Other;
  } else {
    // This code is disabled because it has several problems:
    // One, the actual assumption is wrong, as shown by this code:
    // int "test"(int %X, int %Y) {
    //         %Z = add int %X, %Y
    //         ret int %Z
    // Unreachable:
    //         %Q = add int %X, %Y
    //         ret int %Q
    // }
    //
    // Here there are no shared dominators.  Additionally, this had the habit of
    // moving computations where they were not always computed.  For example, in
    // a case like this:
    //  if (c) {
    //    if (d)  ...
    //    else ... X+Y ...
    //  } else {
    //    ... X+Y ...
    //  }
    //
    // In this case, the expression would be hoisted to outside the 'if' stmt,
    // causing the expression to be evaluated, even for the if (d) path, which
    // could cause problems, if, for example, it caused a divide by zero.  In
    // general the problem this case is trying to solve is better addressed with
    // PRE than GCSE.
    //
    return 0;
  }

  if (isa<LoadInst>(Ret))
    ++NumLoadRemoved;  // Keep track of loads eliminated
  if (isa<CallInst>(Ret))
    ++NumCallRemoved;  // Keep track of calls eliminated
  ++NumInstRemoved;   // Keep track of number of instructions eliminated

  // Add all users of Ret to the worklist...
  for (Value::use_iterator I = Ret->use_begin(), E = Ret->use_end(); I != E;++I)
    if (Instruction *Inst = dyn_cast<Instruction>(*I))
      WorkList.insert(Inst);

  return Ret;
}
<commit_msg>Be more accurate<commit_after>//===-- GCSE.cpp - SSA based Global Common Subexpr Elimination ------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass is designed to be a very quick global transformation that
// eliminates global common subexpressions from a function.  It does this by
// using an existing value numbering implementation to identify the common
// subexpressions, eliminating them when possible.
//
//===----------------------------------------------------------------------===//

#include "llvm/Transforms/Scalar.h"
#include "llvm/iMemory.h"
#include "llvm/iOther.h"
#include "llvm/Type.h"
#include "llvm/Analysis/Dominators.h"
#include "llvm/Analysis/ValueNumbering.h"
#include "llvm/Support/InstIterator.h"
#include "Support/Statistic.h"
#include "Support/Debug.h"
#include <algorithm>
using namespace llvm;

namespace {
  Statistic<> NumInstRemoved("gcse", "Number of instructions removed");
  Statistic<> NumLoadRemoved("gcse", "Number of loads removed");
  Statistic<> NumCallRemoved("gcse", "Number of calls removed");
  Statistic<> NumNonInsts   ("gcse", "Number of instructions removed due "
                             "to non-instruction values");

  class GCSE : public FunctionPass {
    std::set<Instruction*>  WorkList;
    DominatorSet           *DomSetInfo;
    ValueNumbering         *VN;
  public:
    virtual bool runOnFunction(Function &F);

  private:
    bool EliminateRedundancies(Instruction *I,std::vector<Value*> &EqualValues);
    Instruction *EliminateCSE(Instruction *I, Instruction *Other);
    void ReplaceInstWithInst(Instruction *First, BasicBlock::iterator SI);

    // This transformation requires dominator and immediate dominator info
    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
      AU.setPreservesCFG();
      AU.addRequired<DominatorSet>();
      AU.addRequired<ImmediateDominators>();
      AU.addRequired<ValueNumbering>();
    }
  };

  RegisterOpt<GCSE> X("gcse", "Global Common Subexpression Elimination");
}

// createGCSEPass - The public interface to this file...
FunctionPass *llvm::createGCSEPass() { return new GCSE(); }

// GCSE::runOnFunction - This is the main transformation entry point for a
// function.
//
bool GCSE::runOnFunction(Function &F) {
  bool Changed = false;

  // Get pointers to the analysis results that we will be using...
  DomSetInfo = &getAnalysis<DominatorSet>();
  VN = &getAnalysis<ValueNumbering>();

  // Step #1: Add all instructions in the function to the worklist for
  // processing.  All of the instructions are considered to be our
  // subexpressions to eliminate if possible.
  //
  WorkList.insert(inst_begin(F), inst_end(F));

  // Step #2: WorkList processing.  Iterate through all of the instructions,
  // checking to see if there are any additionally defined subexpressions in the
  // program.  If so, eliminate them!
  //
  while (!WorkList.empty()) {
    Instruction &I = **WorkList.begin(); // Get an instruction from the worklist
    WorkList.erase(WorkList.begin());

    // If this instruction computes a value, try to fold together common
    // instructions that compute it.
    //
    if (I.getType() != Type::VoidTy) {
      std::vector<Value*> EqualValues;
      VN->getEqualNumberNodes(&I, EqualValues);

      if (!EqualValues.empty())
        Changed |= EliminateRedundancies(&I, EqualValues);
    }
  }

  // When the worklist is empty, return whether or not we changed anything...
  return Changed;
}

bool GCSE::EliminateRedundancies(Instruction *I,
                                 std::vector<Value*> &EqualValues) {
  // If the EqualValues set contains any non-instruction values, then we know
  // that all of the instructions can be replaced with the non-instruction value
  // because it is guaranteed to dominate all of the instructions in the
  // function.  We only have to do hard work if all we have are instructions.
  //
  for (unsigned i = 0, e = EqualValues.size(); i != e; ++i)
    if (!isa<Instruction>(EqualValues[i])) {
      // Found a non-instruction.  Replace all instructions with the
      // non-instruction.
      //
      Value *Replacement = EqualValues[i];

      // Make sure we get I as well...
      EqualValues[i] = I;

      // Replace all instructions with the Replacement value.
      for (i = 0; i != e; ++i)
        if (Instruction *I = dyn_cast<Instruction>(EqualValues[i])) {
          // Change all users of I to use Replacement.
          I->replaceAllUsesWith(Replacement);

          if (isa<LoadInst>(I))
            ++NumLoadRemoved; // Keep track of loads eliminated
          if (isa<CallInst>(I))
            ++NumCallRemoved; // Keep track of calls eliminated
          ++NumInstRemoved;   // Keep track of number of instructions eliminated
          ++NumNonInsts;      // Keep track of number of insts repl with values

          // Erase the instruction from the program.
          I->getParent()->getInstList().erase(I);
          WorkList.erase(I);
        }

      return true;
    }

  // Remove duplicate entries from EqualValues...
  std::sort(EqualValues.begin(), EqualValues.end());
  EqualValues.erase(std::unique(EqualValues.begin(), EqualValues.end()),
                    EqualValues.end());

  // From this point on, EqualValues is logically a vector of instructions.
  //
  bool Changed = false;
  EqualValues.push_back(I); // Make sure I is included...
  while (EqualValues.size() > 1) {
    // FIXME, this could be done better than simple iteration!
    Instruction *Test = cast<Instruction>(EqualValues.back());
    EqualValues.pop_back();

    for (unsigned i = 0, e = EqualValues.size(); i != e; ++i)
      if (Instruction *Ret = EliminateCSE(Test,
                                          cast<Instruction>(EqualValues[i]))) {
        if (Ret == Test)          // Eliminated EqualValues[i]
          EqualValues[i] = Test;  // Make sure that we reprocess I at some point
        Changed = true;
        break;
      }
  }
  return Changed;
}

// ReplaceInstWithInst - Destroy the instruction pointed to by SI, making all
// uses of the instruction use First now instead.
//
void GCSE::ReplaceInstWithInst(Instruction *First, BasicBlock::iterator SI) {
  Instruction &Second = *SI;

  DEBUG(std::cerr << "GCSE: Substituting %" << First->getName() << " for: "
                  << Second);

  //cerr << "DEL " << (void*)Second << Second;

  // Add the first instruction back to the worklist
  WorkList.insert(First);

  // Add all uses of the second instruction to the worklist
  for (Value::use_iterator UI = Second.use_begin(), UE = Second.use_end();
       UI != UE; ++UI)
    WorkList.insert(cast<Instruction>(*UI));

  // Make all users of 'Second' now use 'First'
  Second.replaceAllUsesWith(First);

  // Erase the second instruction from the program
  Second.getParent()->getInstList().erase(SI);
}

// EliminateCSE - The two instruction I & Other have been found to be common
// subexpressions.  This function is responsible for eliminating one of them,
// and for fixing the worklist to be correct.  The instruction that is preserved
// is returned from the function if the other is eliminated, otherwise null is
// returned.
//
Instruction *GCSE::EliminateCSE(Instruction *I, Instruction *Other) {
  assert(I != Other);

  WorkList.erase(I);
  WorkList.erase(Other); // Other may not actually be on the worklist anymore...

  // Handle the easy case, where both instructions are in the same basic block
  BasicBlock *BB1 = I->getParent(), *BB2 = Other->getParent();
  Instruction *Ret = 0;

  if (BB1 == BB2) {
    // Eliminate the second occurring instruction.  Add all uses of the second
    // instruction to the worklist.
    //
    // Scan the basic block looking for the "first" instruction
    BasicBlock::iterator BI = BB1->begin();
    while (&*BI != I && &*BI != Other) {
      ++BI;
      assert(BI != BB1->end() && "Instructions not found in parent BB!");
    }

    // Keep track of which instructions occurred first & second
    Instruction *First = BI;
    Instruction *Second = I != First ? I : Other; // Get iterator to second inst
    BI = Second;

    if (isa<LoadInst>(Second))
      ++NumLoadRemoved;  // Keep track of loads eliminated
    if (isa<CallInst>(Second))
      ++NumCallRemoved;  // Keep track of calls eliminated

    // Destroy Second, using First instead.
    ReplaceInstWithInst(First, BI);
    Ret = First;

    // Otherwise, the two instructions are in different basic blocks.  If one
    // dominates the other instruction, we can simply use it
    //
  } else if (DomSetInfo->dominates(BB1, BB2)) {    // I dom Other?
    if (isa<LoadInst>(Other))
      ++NumLoadRemoved;  // Keep track of loads eliminated
    if (isa<CallInst>(Other))
      ++NumCallRemoved;  // Keep track of calls eliminated

    ReplaceInstWithInst(I, Other);
    Ret = I;
  } else if (DomSetInfo->dominates(BB2, BB1)) {    // Other dom I?
    if (isa<LoadInst>(I))
      ++NumLoadRemoved;  // Keep track of loads eliminated
    if (isa<CallInst>(I))
      ++NumCallRemoved;  // Keep track of calls eliminated

    ReplaceInstWithInst(Other, I);
    Ret = Other;
  } else {
    // This code is disabled because it has several problems:
    // One, the actual assumption is wrong, as shown by this code:
    // int "test"(int %X, int %Y) {
    //         %Z = add int %X, %Y
    //         ret int %Z
    // Unreachable:
    //         %Q = add int %X, %Y
    //         ret int %Q
    // }
    //
    // Here there are no shared dominators.  Additionally, this had the habit of
    // moving computations where they were not always computed.  For example, in
    // a case like this:
    //  if (c) {
    //    if (d)  ...
    //    else ... X+Y ...
    //  } else {
    //    ... X+Y ...
    //  }
    //
    // In this case, the expression would be hoisted to outside the 'if' stmt,
    // causing the expression to be evaluated, even for the if (d) path, which
    // could cause problems, if, for example, it caused a divide by zero.  In
    // general the problem this case is trying to solve is better addressed with
    // PRE than GCSE.
    //
    return 0;
  }

  ++NumInstRemoved;   // Keep track of number of instructions eliminated

  // Add all users of Ret to the worklist...
  for (Value::use_iterator I = Ret->use_begin(), E = Ret->use_end(); I != E;++I)
    if (Instruction *Inst = dyn_cast<Instruction>(*I))
      WorkList.insert(Inst);

  return Ret;
}
<|endoftext|>


<commit_before>//===-- TypeSymbolTable.cpp - Implement the TypeSymbolTable class ---------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the TypeSymbolTable class for the VMCore library.
//
//===----------------------------------------------------------------------===//

#include "llvm/TypeSymbolTable.h"
#include "llvm/DerivedTypes.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
using namespace llvm;

#define DEBUG_SYMBOL_TABLE 0
#define DEBUG_ABSTYPE 0

TypeSymbolTable::~TypeSymbolTable() {
  // Drop all abstract type references in the type plane...
  for (iterator TI = tmap.begin(), TE = tmap.end(); TI != TE; ++TI) {
    if (TI->second->isAbstract())   // If abstract, drop the reference...
      cast<DerivedType>(TI->second)->removeAbstractTypeUser(this);
  }
}

std::string TypeSymbolTable::getUniqueName(StringRef BaseName) const {
  std::string TryName = BaseName;

  const_iterator End = tmap.end();

  // See if the name exists
  while (tmap.find(TryName) != End)            // Loop until we find a free
    TryName = BaseName.str() + utostr(++LastUnique); // name in the symbol table
  return TryName;
}

// lookup a type by name - returns null on failure
Type* TypeSymbolTable::lookup(StringRef Name) const {
  const_iterator TI = tmap.find(Name);
  Type* result = 0;
  if (TI != tmap.end())
    result = const_cast<Type*>(TI->second);
  return result;
}

// remove - Remove a type from the symbol table...
Type* TypeSymbolTable::remove(iterator Entry) {
  assert(Entry != tmap.end() && "Invalid entry to remove!");
  const Type* Result = Entry->second;

#if DEBUG_SYMBOL_TABLE
  dump();
  errs() << " Removing Value: " << Result->getDescription() << "\n";
#endif

  tmap.erase(Entry);

  // If we are removing an abstract type, remove the symbol table from it's use
  // list...
  if (Result->isAbstract()) {
#if DEBUG_ABSTYPE
    errs() << "Removing abstract type from symtab"
           << Result->getDescription()
           << "\n";
#endif
    cast<DerivedType>(Result)->removeAbstractTypeUser(this);
  }

  return const_cast<Type*>(Result);
}

// insert - Insert a type into the symbol table with the specified name...
void TypeSymbolTable::insert(StringRef Name, const Type* T) {
  assert(T && "Can't insert null type into symbol table!");

  if (tmap.insert(std::make_pair(Name, T)).second) {
    // Type inserted fine with no conflict.

#if DEBUG_SYMBOL_TABLE
    dump();
    errs() << " Inserted type: " << Name << ": " << T->getDescription() << "\n";
#endif
  } else {
    // If there is a name conflict...

    // Check to see if there is a naming conflict.  If so, rename this type!
    std::string UniqueName = Name;
    if (lookup(Name))
      UniqueName = getUniqueName(Name);

#if DEBUG_SYMBOL_TABLE
    dump();
    errs() << " Inserting type: " << UniqueName << ": "
           << T->getDescription() << "\n";
#endif

    // Insert the tmap entry
    tmap.insert(make_pair(UniqueName, T));
  }

  // If we are adding an abstract type, add the symbol table to it's use list.
  if (T->isAbstract()) {
    cast<DerivedType>(T)->addAbstractTypeUser(this);
#if DEBUG_ABSTYPE
    errs() << "Added abstract type to ST: " << T->getDescription() << "\n";
#endif
  }
}

// This function is called when one of the types in the type plane are refined
void TypeSymbolTable::refineAbstractType(const DerivedType *OldType,
                                         const Type *NewType) {
  // Loop over all of the types in the symbol table, replacing any references
  // to OldType with references to NewType.  Note that there may be multiple
  // occurrences, and although we only need to remove one at a time, it's
  // faster to remove them all in one pass.
  //
  for (iterator I = begin(), E = end(); I != E; ++I) {
    if (I->second == (Type*)OldType) {  // FIXME when Types aren't const.
#if DEBUG_ABSTYPE
      errs() << "Removing type " << OldType->getDescription() << "\n";
#endif
      OldType->removeAbstractTypeUser(this);

      I->second = (Type*)NewType;  // TODO FIXME when types aren't const
      if (NewType->isAbstract()) {
#if DEBUG_ABSTYPE
        errs() << "Added type " << NewType->getDescription() << "\n";
#endif
        cast<DerivedType>(NewType)->addAbstractTypeUser(this);
      }
    }
  }
}

// Handle situation where type becomes Concreate from Abstract
void TypeSymbolTable::typeBecameConcrete(const DerivedType *AbsTy) {
  // Loop over all of the types in the symbol table, dropping any abstract
  // type user entries for AbsTy which occur because there are names for the
  // type.
  for (iterator TI = begin(), TE = end(); TI != TE; ++TI)
    if (TI->second == const_cast<Type*>(static_cast<const Type*>(AbsTy)))
      AbsTy->removeAbstractTypeUser(this);
}

static void DumpTypes(const std::pair<const std::string, const Type*>& T ) {
  errs() << "  '" << T.first << "' = ";
  T.second->dump();
  errs() << "\n";
}

void TypeSymbolTable::dump() const {
  errs() << "TypeSymbolPlane: ";
  for_each(tmap.begin(), tmap.end(), DumpTypes);
}

<commit_msg>Change errs() to dbgs().<commit_after>//===-- TypeSymbolTable.cpp - Implement the TypeSymbolTable class ---------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the TypeSymbolTable class for the VMCore library.
//
//===----------------------------------------------------------------------===//

#include "llvm/TypeSymbolTable.h"
#include "llvm/DerivedTypes.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
using namespace llvm;

#define DEBUG_SYMBOL_TABLE 0
#define DEBUG_ABSTYPE 0

TypeSymbolTable::~TypeSymbolTable() {
  // Drop all abstract type references in the type plane...
  for (iterator TI = tmap.begin(), TE = tmap.end(); TI != TE; ++TI) {
    if (TI->second->isAbstract())   // If abstract, drop the reference...
      cast<DerivedType>(TI->second)->removeAbstractTypeUser(this);
  }
}

std::string TypeSymbolTable::getUniqueName(StringRef BaseName) const {
  std::string TryName = BaseName;

  const_iterator End = tmap.end();

  // See if the name exists
  while (tmap.find(TryName) != End)            // Loop until we find a free
    TryName = BaseName.str() + utostr(++LastUnique); // name in the symbol table
  return TryName;
}

// lookup a type by name - returns null on failure
Type* TypeSymbolTable::lookup(StringRef Name) const {
  const_iterator TI = tmap.find(Name);
  Type* result = 0;
  if (TI != tmap.end())
    result = const_cast<Type*>(TI->second);
  return result;
}

// remove - Remove a type from the symbol table...
Type* TypeSymbolTable::remove(iterator Entry) {
  assert(Entry != tmap.end() && "Invalid entry to remove!");
  const Type* Result = Entry->second;

#if DEBUG_SYMBOL_TABLE
  dump();
  dbgs() << " Removing Value: " << Result->getDescription() << "\n";
#endif

  tmap.erase(Entry);

  // If we are removing an abstract type, remove the symbol table from it's use
  // list...
  if (Result->isAbstract()) {
#if DEBUG_ABSTYPE
    dbgs() << "Removing abstract type from symtab"
           << Result->getDescription()
           << "\n";
#endif
    cast<DerivedType>(Result)->removeAbstractTypeUser(this);
  }

  return const_cast<Type*>(Result);
}

// insert - Insert a type into the symbol table with the specified name...
void TypeSymbolTable::insert(StringRef Name, const Type* T) {
  assert(T && "Can't insert null type into symbol table!");

  if (tmap.insert(std::make_pair(Name, T)).second) {
    // Type inserted fine with no conflict.

#if DEBUG_SYMBOL_TABLE
    dump();
    dbgs() << " Inserted type: " << Name << ": " << T->getDescription() << "\n";
#endif
  } else {
    // If there is a name conflict...

    // Check to see if there is a naming conflict.  If so, rename this type!
    std::string UniqueName = Name;
    if (lookup(Name))
      UniqueName = getUniqueName(Name);

#if DEBUG_SYMBOL_TABLE
    dump();
    dbgs() << " Inserting type: " << UniqueName << ": "
           << T->getDescription() << "\n";
#endif

    // Insert the tmap entry
    tmap.insert(make_pair(UniqueName, T));
  }

  // If we are adding an abstract type, add the symbol table to it's use list.
  if (T->isAbstract()) {
    cast<DerivedType>(T)->addAbstractTypeUser(this);
#if DEBUG_ABSTYPE
    dbgs() << "Added abstract type to ST: " << T->getDescription() << "\n";
#endif
  }
}

// This function is called when one of the types in the type plane are refined
void TypeSymbolTable::refineAbstractType(const DerivedType *OldType,
                                         const Type *NewType) {
  // Loop over all of the types in the symbol table, replacing any references
  // to OldType with references to NewType.  Note that there may be multiple
  // occurrences, and although we only need to remove one at a time, it's
  // faster to remove them all in one pass.
  //
  for (iterator I = begin(), E = end(); I != E; ++I) {
    if (I->second == (Type*)OldType) {  // FIXME when Types aren't const.
#if DEBUG_ABSTYPE
      dbgs() << "Removing type " << OldType->getDescription() << "\n";
#endif
      OldType->removeAbstractTypeUser(this);

      I->second = (Type*)NewType;  // TODO FIXME when types aren't const
      if (NewType->isAbstract()) {
#if DEBUG_ABSTYPE
        dbgs() << "Added type " << NewType->getDescription() << "\n";
#endif
        cast<DerivedType>(NewType)->addAbstractTypeUser(this);
      }
    }
  }
}

// Handle situation where type becomes Concreate from Abstract
void TypeSymbolTable::typeBecameConcrete(const DerivedType *AbsTy) {
  // Loop over all of the types in the symbol table, dropping any abstract
  // type user entries for AbsTy which occur because there are names for the
  // type.
  for (iterator TI = begin(), TE = end(); TI != TE; ++TI)
    if (TI->second == const_cast<Type*>(static_cast<const Type*>(AbsTy)))
      AbsTy->removeAbstractTypeUser(this);
}

static void DumpTypes(const std::pair<const std::string, const Type*>& T ) {
  dbgs() << "  '" << T.first << "' = ";
  T.second->dump();
  dbgs() << "\n";
}

void TypeSymbolTable::dump() const {
  dbgs() << "TypeSymbolPlane: ";
  for_each(tmap.begin(), tmap.end(), DumpTypes);
}

<|endoftext|>


<commit_before>/*

This is a harder problem right now:

Qt 5.X implements signals in a very different way.
In order to get the best possible result in very little time, I (ctismer) decided to
create these functions as defunct definitions, in order to do them right, pretty soon.
For today, I don't have the brains for that!

static bool isDecorator(PyObject* method, PyObject* self)
{
    Shiboken::AutoDecRef methodName(PyObject_GetAttrString(method, "__name__"));
    if (!PyObject_HasAttr(self, methodName))
        return true;
    Shiboken::AutoDecRef otherMethod(PyObject_GetAttr(self, methodName));
    return reinterpret_cast<PyMethodObject*>(otherMethod.object())->im_func != \
           reinterpret_cast<PyMethodObject*>(method)->im_func;
}

static bool getReceiver(QObject *source, const char* signal, PyObject* callback, QObject** receiver, PyObject** self, QByteArray* callbackSig)
{
    bool forceGlobalReceiver = false;
    if (PyMethod_Check(callback)) {
        *self = PyMethod_GET_SELF(callback);
        if (%CHECKTYPE[QObject*](*self))
            *receiver = %CONVERTTOCPP[QObject*](*self);
        forceGlobalReceiver = isDecorator(callback, *self);
    } else if (PyCFunction_Check(callback)) {
        *self = PyCFunction_GET_SELF(callback);
        if (*self && %CHECKTYPE[QObject*](*self))
            *receiver = %CONVERTTOCPP[QObject*](*self);
    } else if (PyCallable_Check(callback)) {
        // Ok, just a callable object
        *receiver = 0;
        *self = 0;
    }

    bool usingGlobalReceiver = !*receiver || forceGlobalReceiver;

    // Check if this callback is a overwrite of a non-virtual Qt slot.
    if (!usingGlobalReceiver && receiver && self) {
        *callbackSig = PySide::Signal::getCallbackSignature(signal, *receiver, callback, usingGlobalReceiver).toUtf8();
        const QMetaObject* metaObject = (*receiver)->metaObject();
        int slotIndex = metaObject->indexOfSlot(callbackSig->constData());
        if (slotIndex != -1 && slotIndex < metaObject->methodOffset() && PyMethod_Check(callback))
            usingGlobalReceiver = true;
    }

    if (usingGlobalReceiver) {
        PySide::SignalManager& signalManager = PySide::SignalManager::instance();
        *receiver = signalManager.globalReceiver(source, callback);
        *callbackSig = PySide::Signal::getCallbackSignature(signal, *receiver, callback, usingGlobalReceiver).toUtf8();
    }

    return usingGlobalReceiver;
}

static QMetaObject::Connection qobjectConnect(QObject* source, const char* signal, QObject* receiver, const char* slot, Qt::ConnectionType type)
{
    if (!signal || !slot)
        return QMetaObject::Connection();

    if (!PySide::Signal::checkQtSignal(signal))
        return QMetaObject::Connection();
    signal++;

    if (!PySide::SignalManager::registerMetaMethod(source, signal, QMetaMethod::Signal))
        return QMetaObject::Connection();

    bool isSignal = PySide::Signal::isQtSignal(slot);
    slot++;
    PySide::SignalManager::registerMetaMethod(receiver, slot, isSignal ? QMetaMethod::Signal : QMetaMethod::Slot);
    QMetaObject::Connection connection;
    Py_BEGIN_ALLOW_THREADS
    connection = QObject::connect(source, signal - 1, receiver, slot - 1, type);
    Py_END_ALLOW_THREADS
    return connection;
}

static QMetaObject::Connection qobjectConnectCallback(QObject* source, const char* signal, PyObject* callback, Qt::ConnectionType type)
{
    if (!signal || !PySide::Signal::checkQtSignal(signal))
        return QMetaObject::Connection();
    signal++;

    int signalIndex = PySide::SignalManager::registerMetaMethodGetIndex(source, signal, QMetaMethod::Signal);
    if (signalIndex == -1)
        return QMetaObject::Connection();

    PySide::SignalManager& signalManager = PySide::SignalManager::instance();

    // Extract receiver from callback
    QObject* receiver = 0;
    PyObject* self = 0;
    QByteArray callbackSig;
    bool usingGlobalReceiver = getReceiver(source, signal, callback, &receiver, &self, &callbackSig);
    if (receiver == 0 && self == 0)
        return QMetaObject::Connection();

    const QMetaObject* metaObject = receiver->metaObject();
    const char* slot = callbackSig.constData();
    int slotIndex = metaObject->indexOfSlot(slot);

    if (slotIndex == -1) {
        if (!usingGlobalReceiver && self && !Shiboken::Object::hasCppWrapper((SbkObject*)self)) {
            qWarning() << "You can't add dynamic slots on an object originated from C++.";
            if (usingGlobalReceiver)
                signalManager.releaseGlobalReceiver(source, receiver);

            return QMetaObject::Connection();
        }

        if (usingGlobalReceiver)
            slotIndex = signalManager.globalReceiverSlotIndex(receiver, slot);
        else
            slotIndex = PySide::SignalManager::registerMetaMethodGetIndex(receiver, slot, QMetaMethod::Slot);

        if (slotIndex == -1) {
            if (usingGlobalReceiver)
                signalManager.releaseGlobalReceiver(source, receiver);

            return QMetaObject::Connection();
        }
    }
    QMetaObject::Connection connection;
    Py_BEGIN_ALLOW_THREADS
    connection = QMetaObject::connect(source, signalIndex, receiver, slotIndex, type);
    Py_END_ALLOW_THREADS
    if (connection) {
        if (usingGlobalReceiver)
            signalManager.notifyGlobalReceiver(receiver);
        #ifndef AVOID_PROTECTED_HACK
            source->connectNotify(signal - 1);
        #else
            // Need to cast to QObjectWrapper* and call the public version of
            // connectNotify when avoiding the protected hack.
            reinterpret_cast<QObjectWrapper*>(source)->connectNotify(signal - 1);
        #endif

        return connection;
    }

    if (usingGlobalReceiver)
        signalManager.releaseGlobalReceiver(source, receiver);

    return QMetaObject::Connection();
}

static bool qobjectDisconnectCallback(QObject* source, const char* signal, PyObject* callback)
{
    if (!PySide::Signal::checkQtSignal(signal))
        return false;

    PySide::SignalManager& signalManager = PySide::SignalManager::instance();

    // Extract receiver from callback
    QObject* receiver = 0;
    PyObject* self = 0;
    QByteArray callbackSig;
    bool usingGlobalReceiver = getReceiver(NULL, signal, callback, &receiver, &self, &callbackSig);
    if (receiver == 0 && self == 0)
        return false;

    const QMetaObject* metaObject = receiver->metaObject();
    int signalIndex = source->metaObject()->indexOfSignal(++signal);
    int slotIndex = -1;

    slotIndex = metaObject->indexOfSlot(callbackSig);

    bool disconnected;
    Py_BEGIN_ALLOW_THREADS
    disconnected = QMetaObject::disconnectOne(source, signalIndex, receiver, slotIndex);
    Py_END_ALLOW_THREADS

    if (disconnected) {
        if (usingGlobalReceiver)
            signalManager.releaseGlobalReceiver(source, receiver);

        #ifndef AVOID_PROTECTED_HACK
            source->disconnectNotify(callbackSig);
        #else
            // Need to cast to QObjectWrapper* and call the public version of
            // connectNotify when avoiding the protected hack.
            reinterpret_cast<QObjectWrapper*>(source)->disconnectNotify(callbackSig);
        #endif
        return true;
    }
    return false;
}

*/

// the temporary definitions may follow, soon:

<commit_msg>apply Romain's fixes to object_connect.cpp<commit_after>
static bool isDecorator(PyObject* method, PyObject* self)
{
    Shiboken::AutoDecRef methodName(PyObject_GetAttrString(method, "__name__"));
    if (!PyObject_HasAttr(self, methodName))
        return true;
    Shiboken::AutoDecRef otherMethod(PyObject_GetAttr(self, methodName));
    return reinterpret_cast<PyMethodObject*>(otherMethod.object())->im_func != \
           reinterpret_cast<PyMethodObject*>(method)->im_func;
}

static bool getReceiver(QObject *source, const char* signal, PyObject* callback, QObject** receiver, PyObject** self, QByteArray* callbackSig)
{
    bool forceGlobalReceiver = false;
    if (PyMethod_Check(callback)) {
        *self = PyMethod_GET_SELF(callback);
        if (%CHECKTYPE[QObject*](*self))
            *receiver = %CONVERTTOCPP[QObject*](*self);
        forceGlobalReceiver = isDecorator(callback, *self);
    } else if (PyCFunction_Check(callback)) {
        *self = PyCFunction_GET_SELF(callback);
        if (*self && %CHECKTYPE[QObject*](*self))
            *receiver = %CONVERTTOCPP[QObject*](*self);
    } else if (PyCallable_Check(callback)) {
        // Ok, just a callable object
        *receiver = 0;
        *self = 0;
    }

    bool usingGlobalReceiver = !*receiver || forceGlobalReceiver;

    // Check if this callback is a overwrite of a non-virtual Qt slot.
    if (!usingGlobalReceiver && receiver && self) {
        *callbackSig = PySide::Signal::getCallbackSignature(signal, *receiver, callback, usingGlobalReceiver).toLatin1();
        const QMetaObject* metaObject = (*receiver)->metaObject();
        int slotIndex = metaObject->indexOfSlot(callbackSig->constData());
        if (slotIndex != -1 && slotIndex < metaObject->methodOffset() && PyMethod_Check(callback))
            usingGlobalReceiver = true;
    }

    if (usingGlobalReceiver) {
        PySide::SignalManager& signalManager = PySide::SignalManager::instance();
        *receiver = signalManager.globalReceiver(source, callback);
        *callbackSig = PySide::Signal::getCallbackSignature(signal, *receiver, callback, usingGlobalReceiver).toLatin1();
    }

    return usingGlobalReceiver;
}

static QMetaObject::Connection qobjectConnect(QObject* source, const char* signal, QObject* receiver, const char* slot, Qt::ConnectionType type)
{
    if (!signal || !slot)
        return QMetaObject::Connection();

    if (!PySide::Signal::checkQtSignal(signal))
        return QMetaObject::Connection();
    signal++;

    if (!PySide::SignalManager::registerMetaMethod(source, signal, QMetaMethod::Signal))
        return QMetaObject::Connection();

    bool isSignal = PySide::Signal::isQtSignal(slot);
    slot++;
    PySide::SignalManager::registerMetaMethod(receiver, slot, isSignal ? QMetaMethod::Signal : QMetaMethod::Slot);
    QMetaObject::Connection connection;
    Py_BEGIN_ALLOW_THREADS
    connection = QObject::connect(source, signal - 1, receiver, slot - 1, type);
    Py_END_ALLOW_THREADS
    return connection;
}

static QMetaObject::Connection qobjectConnectCallback(QObject* source, const char* signal, PyObject* callback, Qt::ConnectionType type)
{
    if (!signal || !PySide::Signal::checkQtSignal(signal))
        return QMetaObject::Connection();
    signal++;

    int signalIndex = PySide::SignalManager::registerMetaMethodGetIndex(source, signal, QMetaMethod::Signal);
    if (signalIndex == -1)
        return QMetaObject::Connection();

    PySide::SignalManager& signalManager = PySide::SignalManager::instance();

    // Extract receiver from callback
    QObject* receiver = 0;
    PyObject* self = 0;
    QByteArray callbackSig;
    bool usingGlobalReceiver = getReceiver(source, signal, callback, &receiver, &self, &callbackSig);
    if (receiver == 0 && self == 0)
        return QMetaObject::Connection();

    const QMetaObject* metaObject = receiver->metaObject();
    const char* slot = callbackSig.constData();
    int slotIndex = metaObject->indexOfSlot(slot);
    QMetaMethod signalMethod = metaObject->method(signalIndex);

    if (slotIndex == -1) {
        if (!usingGlobalReceiver && self && !Shiboken::Object::hasCppWrapper((SbkObject*)self)) {
            qWarning() << "You can't add dynamic slots on an object originated from C++.";
            if (usingGlobalReceiver)
                signalManager.releaseGlobalReceiver(source, receiver);

            return QMetaObject::Connection();
        }

        if (usingGlobalReceiver)
            slotIndex = signalManager.globalReceiverSlotIndex(receiver, slot);
        else
            slotIndex = PySide::SignalManager::registerMetaMethodGetIndex(receiver, slot, QMetaMethod::Slot);

        if (slotIndex == -1) {
            if (usingGlobalReceiver)
                signalManager.releaseGlobalReceiver(source, receiver);

            return QMetaObject::Connection();
        }
    }
    QMetaObject::Connection connection;
    Py_BEGIN_ALLOW_THREADS
    connection = QMetaObject::connect(source, signalIndex, receiver, slotIndex, type);
    Py_END_ALLOW_THREADS
    if (connection) {
        if (usingGlobalReceiver)
            signalManager.notifyGlobalReceiver(receiver);
        #ifndef AVOID_PROTECTED_HACK
            source->connectNotify(signalMethod); //Qt5: QMetaMethod instead of char*
        #else
            // Need to cast to QObjectWrapper* and call the public version of
            // connectNotify when avoiding the protected hack.
            reinterpret_cast<QObjectWrapper*>(source)->connectNotify(signalMethod); //Qt5: QMetaMethod instead of char*
        #endif

        return connection;
    }

    if (usingGlobalReceiver)
        signalManager.releaseGlobalReceiver(source, receiver);

    return QMetaObject::Connection();
}

static bool qobjectDisconnectCallback(QObject* source, const char* signal, PyObject* callback)
{
    if (!PySide::Signal::checkQtSignal(signal))
        return false;

    PySide::SignalManager& signalManager = PySide::SignalManager::instance();

    // Extract receiver from callback
    QObject* receiver = 0;
    PyObject* self = 0;
    QByteArray callbackSig;
    QMetaMethod slotMethod;
    bool usingGlobalReceiver = getReceiver(NULL, signal, callback, &receiver, &self, &callbackSig);
    if (receiver == 0 && self == 0)
        return false;

    const QMetaObject* metaObject = receiver->metaObject();
    int signalIndex = source->metaObject()->indexOfSignal(++signal);
    int slotIndex = -1;

    slotIndex = metaObject->indexOfSlot(callbackSig);
    slotMethod = metaObject->method(slotIndex);

    bool disconnected;
    Py_BEGIN_ALLOW_THREADS
    disconnected = QMetaObject::disconnectOne(source, signalIndex, receiver, slotIndex);
    Py_END_ALLOW_THREADS

    if (disconnected) {
        if (usingGlobalReceiver)
            signalManager.releaseGlobalReceiver(source, receiver);

        #ifndef AVOID_PROTECTED_HACK
            source->disconnectNotify(slotMethod); //Qt5: QMetaMethod instead of char*
        #else
            // Need to cast to QObjectWrapper* and call the public version of
            // connectNotify when avoiding the protected hack.
            reinterpret_cast<QObjectWrapper*>(source)->disconnectNotify(slotMethod); //Qt5: QMetaMethod instead of char*
        #endif
        return true;
    }
    return false;
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: scendlg.hxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 21:47:33 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef SC_SCENDLG_HXX
#define SC_SCENDLG_HXX

#ifndef _SV_DIALOG_HXX //autogen
#include <vcl/dialog.hxx>
#endif

#ifndef _SV_EDIT_HXX //autogen
#include <vcl/edit.hxx>
#endif

#ifndef _SV_FIXED_HXX //autogen
#include <vcl/fixed.hxx>
#endif

#ifndef _SV_BUTTON_HXX //autogen
#include <vcl/imagebtn.hxx>
#endif

#ifndef _SVEDIT_HXX //autogen
#include <svtools/svmedit.hxx>
#endif

#ifndef _CTRLBOX_HXX //autogen
#include <svtools/ctrlbox.hxx>
#endif

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

class ScNewScenarioDlg : public ModalDialog
{
public:
        ScNewScenarioDlg( Window* pParent, const String& rName, BOOL bEdit = FALSE, BOOL bSheetProtected = FALSE );
        ~ScNewScenarioDlg();

    void SetScenarioData( const String& rName, const String& rComment,
                            const Color& rColor, USHORT nFlags );

    void GetScenarioData( String& rName, String& rComment,
                            Color& rColor, USHORT& rFlags ) const;

private:
    FixedLine           aFlName;
    Edit                aEdName;
    FixedLine           aFlComment;
    MultiLineEdit       aEdComment;
    FixedLine           aFlOptions;
    CheckBox            aCbShowFrame;
    ColorListBox        aLbColor;
    //CheckBox          aCbPrintFrame;
    CheckBox            aCbTwoWay;
    //CheckBox          aCbAttrib;
    //CheckBox          aCbValue;
    CheckBox            aCbCopyAll;
    CheckBox            aCbProtect;
    OKButton            aBtnOk;
    CancelButton        aBtnCancel;
    HelpButton          aBtnHelp;
    const String        aDefScenarioName;
    BOOL                bIsEdit;

    DECL_LINK( OkHdl, OKButton * );
    DECL_LINK( EnableHdl, CheckBox * );
};

#endif // SC_SCENDLG_HXX

<commit_msg>INTEGRATION: CWS changefileheader (1.4.700); FILE MERGED 2008/04/01 15:30:59 thb 1.4.700.2: #i85898# Stripping all external header guards 2008/03/31 17:15:47 rt 1.4.700.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: scendlg.hxx,v $
 * $Revision: 1.5 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef SC_SCENDLG_HXX
#define SC_SCENDLG_HXX

#include <vcl/dialog.hxx>
#include <vcl/edit.hxx>
#include <vcl/fixed.hxx>
#include <vcl/imagebtn.hxx>
#include <svtools/svmedit.hxx>
#include <svtools/ctrlbox.hxx>

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

class ScNewScenarioDlg : public ModalDialog
{
public:
        ScNewScenarioDlg( Window* pParent, const String& rName, BOOL bEdit = FALSE, BOOL bSheetProtected = FALSE );
        ~ScNewScenarioDlg();

    void SetScenarioData( const String& rName, const String& rComment,
                            const Color& rColor, USHORT nFlags );

    void GetScenarioData( String& rName, String& rComment,
                            Color& rColor, USHORT& rFlags ) const;

private:
    FixedLine           aFlName;
    Edit                aEdName;
    FixedLine           aFlComment;
    MultiLineEdit       aEdComment;
    FixedLine           aFlOptions;
    CheckBox            aCbShowFrame;
    ColorListBox        aLbColor;
    //CheckBox          aCbPrintFrame;
    CheckBox            aCbTwoWay;
    //CheckBox          aCbAttrib;
    //CheckBox          aCbValue;
    CheckBox            aCbCopyAll;
    CheckBox            aCbProtect;
    OKButton            aBtnOk;
    CancelButton        aBtnCancel;
    HelpButton          aBtnHelp;
    const String        aDefScenarioName;
    BOOL                bIsEdit;

    DECL_LINK( OkHdl, OKButton * );
    DECL_LINK( EnableHdl, CheckBox * );
};

#endif // SC_SCENDLG_HXX

<|endoftext|>


<commit_before>#include "GroupTreeCtrl.h"
#include "GroupTreePanel.h"
#include "MultiSpritesImpl.h"
#include "GroupTreeImpl.h"
#include "ViewPanelMgr.h"

#include "dataset/Group.h"
#include "dataset/ISprite.h"

#include <sstream>
#include <queue>
#include <wx/menu.h>

namespace d2d
{

BEGIN_EVENT_TABLE(GroupTreeCtrl, wxTreeCtrl)
	EVT_TREE_ITEM_RIGHT_CLICK(ID_GROUP_TREE_CTRL, GroupTreeCtrl::OnItemRClick)
	EVT_TREE_ITEM_MENU(ID_GROUP_TREE_CTRL, GroupTreeCtrl::OnItemMenu)
	EVT_TREE_ITEM_ACTIVATED(ID_GROUP_TREE_CTRL, GroupTreeCtrl::OnItemActivated)
	EVT_TREE_BEGIN_DRAG(ID_GROUP_TREE_CTRL, GroupTreeCtrl::OnBeginDrag)
	EVT_TREE_END_DRAG(ID_GROUP_TREE_CTRL, GroupTreeCtrl::OnEndDrag)
	EVT_KEY_DOWN(GroupTreeCtrl::OnKeyDown)
	EVT_TREE_SEL_CHANGED(ID_GROUP_TREE_CTRL, GroupTreeCtrl::OnSelChanged)
END_EVENT_TABLE()

GroupTreeCtrl::GroupTreeCtrl(GroupTreePanel* parent, MultiSpritesImpl* sprite_impl,
							 ViewPanelMgr* view_panel_mgr)
	: wxTreeCtrl(parent, ID_GROUP_TREE_CTRL, wxDefaultPosition, wxDefaultSize,
	wxTR_EDIT_LABELS | /*wxTR_HIDE_ROOT | */wxTR_NO_LINES | wxTR_DEFAULT_STYLE)
	, m_parent_panel(parent)
	, m_sprite_impl(sprite_impl)
	, m_view_panel_mgr(view_panel_mgr)
	, m_remove_open(true)
{
	InitRoot();
}

void GroupTreeCtrl::Traverse(IGroupTreeVisitor& visitor) const
{
	Traverse(m_root, visitor);
}

wxTreeItemId GroupTreeCtrl::AddNode()
{
	static int s_num = 0;

	std::ostringstream ss;
	ss << "GROUP_" << s_num++;
	std::string text = ss.str();

	return AddNode(text);
}

wxTreeItemId GroupTreeCtrl::AddNode(const std::string& name)
{
	GroupTreeItem* data = new GroupTreeItem(new Group(name));

	wxTreeItemId ret;
	wxTreeItemId id = GetFocusedItem();
	if (id.IsOk()) {
		data->SetId(id);
		ret = AddNode(id, name, data);
	} else {
		data->SetId(m_root);
		ret = AddNode(m_root, name, data);
	}
	SetItemBold(ret, true);
	return ret;
}

wxTreeItemId GroupTreeCtrl::AddNode(const std::string& name, wxTreeItemId parent)
{
	GroupTreeItem* data = new GroupTreeItem(new Group(name));
	wxTreeItemId ret = AddNode(parent, name, data);
	SetItemBold(ret, true);
	return ret;
}

void GroupTreeCtrl::DelNode()
{
	wxTreeItemId id = GetFocusedItem();
	if (id.IsOk()) {
		Delete(id);
	}
}

wxTreeItemId GroupTreeCtrl::AddSprite(wxTreeItemId parent, d2d::ISprite* spr)
{
	if (!parent.IsOk()) {
		return m_root;
	}

	GroupTreeItem* data = (GroupTreeItem*)GetItemData(parent);
	if (!data) {
		return m_root;
	}

	Group* group = data->m_group;
	if (!group) {
		return m_root;
	}

	bool ok = group->Insert(spr);
	if (ok) {
		GroupTreeItem* data = new GroupTreeItem(spr);
		return AddNode(parent, spr->name, data);
	} else {
		return m_root;
	}
}

wxTreeItemId GroupTreeCtrl::AddSprite(d2d::ISprite* spr)
{
	wxTreeItemId ret;
	if (m_selected_item.IsOk()) {
		ret = AddSprite(m_selected_item, spr);
	}
	if (!ret.IsOk() || ret == m_root) {
		assert(m_root.IsOk());
		ret = AddSprite(m_root, spr);
	}
	return ret;
}

void GroupTreeCtrl::Clear()
{
	if (!IsEmpty()) {
		CollapseAndReset(m_root);
	}
}

void GroupTreeCtrl::Remove(ISprite* sprite)
{
	if (m_remove_open) {
		Traverse(GroupTreeImpl::RemoveVisitor(this, sprite));
	}
}

void GroupTreeCtrl::Visible(wxTreeItemId id, bool visible)
{
	Traverse(id, GroupTreeImpl::SetVisibleVisitor(this, visible));
}

void GroupTreeCtrl::Editable(wxTreeItemId id, bool editable)
{
	Traverse(id, GroupTreeImpl::SetEditableVisitor(this, editable));
}

void GroupTreeCtrl::ReorderItem(wxTreeItemId id, bool up)
{
	if (!id.IsOk()) {
		return;
	}

	wxTreeItemId insert_prev;
	if (up) {
		wxTreeItemId prev = GetPrevSibling(id);
		if (!prev.IsOk()) {
			return;
		}
		insert_prev = GetPrevSibling(prev);
	} else {
		wxTreeItemId next = GetNextSibling(id);
		if (!next.IsOk()) {
			return;
		}
		insert_prev = next;
	}

	// old info
	GroupTreeItem* data = (GroupTreeItem*)GetItemData(id);
	std::string name = GetItemText(id);

	// insert
	wxTreeItemId parent = GetItemParent(id);
	wxTreeItemId new_item;
	if (insert_prev.IsOk()) {
		new_item = InsertItem(parent, insert_prev, name, -1, -1, data->Clone());
	} else {
		new_item = InsertItem(parent, 0, name, -1, -1, data->Clone());
	}
	ExpandAll();
	// copy older's children
	Traverse(id, GroupTreeImpl::CopyPasteVisitor(this, id, new_item));
	// remove
	Delete(id);
	// sort
	ReorderSprites();
	// set selection
	SelectItem(new_item);
}

wxTreeItemId GroupTreeCtrl::AddNode(wxTreeItemId parent, const std::string& name, GroupTreeItem* data)
{
	wxTreeItemId id = InsertItem(parent, 0, name, -1, -1, data);
	ExpandAll();
	return id;
}

void GroupTreeCtrl::InitRoot()
{
	GroupTreeItem* data = new GroupTreeItem(new Group("ROOT"));
	m_root = AddRoot("ROOT");
	SetItemBold(m_root, true);
	SetItemData(m_root, data);
}

void GroupTreeCtrl::OnItemRClick(wxTreeEvent& event)
{
	wxTreeItemId itemId = event.GetItem();

	GroupTreeItem* item = (GroupTreeItem*)GetItemData(itemId);

	event.Skip();
}

void GroupTreeCtrl::OnItemMenu(wxTreeEvent& event)
{
	wxTreeItemId id = event.GetItem();
	if (!id.IsOk()) {
		return;
	}

	wxPoint clientpt = event.GetPoint();
	wxPoint screenpt = ClientToScreen(clientpt);
	ShowMenu(id, clientpt);
	event.Skip();
}

void GroupTreeCtrl::OnItemActivated(wxTreeEvent& event)
{
	wxTreeItemId id = event.GetItem();
	SpriteSelection* selection = m_sprite_impl->getSpriteSelection();
	selection->Clear();
	Traverse(id, GroupTreeImpl::SelectVisitor(this, selection));
}

void GroupTreeCtrl::OnBeginDrag(wxTreeEvent& event)
{
	m_dragged_item = event.GetItem();
	event.Allow();
}

void GroupTreeCtrl::OnEndDrag(wxTreeEvent& event)
{
	wxTreeItemId item_src = m_dragged_item,
		item_dst = event.GetItem();
	if (!item_dst.IsOk()) {
		return;
	}

	wxLogDebug("Drag from %s to %s", GetItemText(item_src), GetItemText(item_dst));

	// old info
	GroupTreeItem* data = (GroupTreeItem*)GetItemData(item_src);
	std::string name = GetItemText(item_src);
	// insert
	wxTreeItemId new_item = InsertItem(item_dst, 0, name, -1, -1, data->Clone());
	ExpandAll();
	// copy older's children
	Traverse(item_src, GroupTreeImpl::CopyPasteVisitor(this, item_src, new_item));
	// remove
	Delete(item_src);
	// sort
	ReorderSprites();
}

void GroupTreeCtrl::OnKeyDown(wxKeyEvent& event)
{
	switch (event.GetKeyCode())
	{
	case WXK_UP:
		SelectUp();
		break;
	case WXK_DOWN:
		SelectDown();
		break;
	case WXK_LEFT:
		SelectLeft();
		break;
	case WXK_RIGHT:
		SelectRight();
		break;
	case WXK_PAGEUP:
		ReorderItem(m_selected_item, true);
		break;
	case WXK_PAGEDOWN:
		ReorderItem(m_selected_item, false);
		break;
	}
}

void GroupTreeCtrl::OnSelChanged(wxTreeEvent& event)
{
	m_selected_item = event.GetItem();

	wxLogDebug("OnSelChanged %s", GetItemText(m_selected_item));

	GroupTreeItem* data = (GroupTreeItem*)GetItemData(m_selected_item);
	if (data && data->m_sprite) {
		m_view_panel_mgr->SelectSprite(data->m_sprite, m_parent_panel);
	}
}

void GroupTreeCtrl::OnMenuAddSprites(wxCommandEvent& event)
{
	if (!m_on_menu_id.IsOk()) {
		return;
	}

	GroupTreeItem* data = (GroupTreeItem*)GetItemData(m_on_menu_id);
	if (!data) {
		return;
	}

	Group* group = data->m_group;
	if (!group) {
		return;
	}

	SpriteSelection* selection = m_sprite_impl->getSpriteSelection();
	std::vector<ISprite*> sprites;
	selection->Traverse(FetchAllVisitor<ISprite>(sprites));
	for (int i = 0, n = sprites.size(); i < n; ++i) {
		ISprite* spr = sprites[i];
		bool ok = group->Insert(spr);
		if (ok) {
			GroupTreeItem* data = new GroupTreeItem(spr);
			AddNode(m_on_menu_id, spr->name, data);
		}
	}
}

void GroupTreeCtrl::OnMenuClear(wxCommandEvent& event)
{
	if (!m_on_menu_id.IsOk()) {
		return;
	}

	Group* group = ((GroupTreeItem*)GetItemData(m_on_menu_id))->m_group;
	if (!group) {
		return;
	}

	group->Clear();
	CollapseAndReset(m_on_menu_id);
}

void GroupTreeCtrl::OnMenuVisible(wxCommandEvent& event)
{
	Traverse(m_on_menu_id, GroupTreeImpl::VisibleVisitor(this));
}

void GroupTreeCtrl::OnMenuEditable(wxCommandEvent& event)
{
	Traverse(m_on_menu_id, GroupTreeImpl::EditableVisitor(this));
}

void GroupTreeCtrl::SelectUp()
{
	if (!m_selected_item.IsOk()) {
		return;
	}

	wxTreeItemId prev = GetPrevSibling(m_selected_item);
	if (prev.IsOk()) {
		SelectItem(prev);
	}
}

void GroupTreeCtrl::SelectDown()
{
	if (!m_selected_item.IsOk()) {
		return;
	}

	wxTreeItemId next = GetNextSibling(m_selected_item);
	if (next.IsOk()) {
		SelectItem(next);
	}
}

void GroupTreeCtrl::SelectLeft()
{
	if (!m_selected_item.IsOk()) {
		return;
	}

	if (ItemHasChildren(m_selected_item) && IsExpanded(m_selected_item)) {
		Collapse(m_selected_item);
	} else {
	 	wxTreeItemId parent = GetItemParent(m_selected_item);
	 	if (parent.IsOk() && parent != m_root) {
	 		SelectItem(parent);
	 	}
	}
}

void GroupTreeCtrl::SelectRight()
{
	if (!m_selected_item.IsOk()) {
		return;
	}

	if (ItemHasChildren(m_selected_item)) {
		if (IsExpanded(m_selected_item)) {
			wxTreeItemIdValue cookie;
			wxTreeItemId next = GetFirstChild(m_selected_item, cookie);
			if (next.IsOk()) {
				SelectItem(next);
			}
		} else {
			Expand(m_selected_item);
		}
	}
}

void GroupTreeCtrl::ReorderSprites()
{
	std::vector<ISprite*> sprites;
	Traverse(m_root, GroupTreeImpl::GetSpritesVisitor(this, sprites));
	for (int i = sprites.size() - 1; i >= 0; --i) {
		ISprite* spr = sprites[i];
		m_remove_open = false;
		m_sprite_impl->removeSprite(spr);
		m_remove_open = true;
		m_sprite_impl->insertSprite(spr);
	}
}

void GroupTreeCtrl::ShowMenu(wxTreeItemId id, const wxPoint& pt)
{
	m_on_menu_id = id;

	wxMenu menu;

	menu.Append(ID_MENU_ADD, wxT("&Add Sprites"));
	Bind(wxEVT_COMMAND_MENU_SELECTED, &GroupTreeCtrl::OnMenuAddSprites, this, ID_MENU_ADD);

	menu.Append(ID_MENU_CLEAR, wxT("&Clear Sprites"));
	Bind(wxEVT_COMMAND_MENU_SELECTED, &GroupTreeCtrl::OnMenuClear, this, ID_MENU_CLEAR);

	menu.AppendSeparator();

	menu.AppendCheckItem(ID_MENU_VISIBLE, wxT("&Visible"));
	Bind(wxEVT_COMMAND_MENU_SELECTED, &GroupTreeCtrl::OnMenuVisible, this, ID_MENU_VISIBLE);

	menu.AppendCheckItem(ID_MENU_EDITABLE, wxT("&Editable"));
	Bind(wxEVT_COMMAND_MENU_SELECTED, &GroupTreeCtrl::OnMenuEditable, this, ID_MENU_EDITABLE);

	PopupMenu(&menu, pt);
}

void GroupTreeCtrl::Traverse(wxTreeItemId id, IGroupTreeVisitor& visitor) const
{
	std::queue<wxTreeItemId> buf;
	buf.push(id);
	while (!buf.empty()) {
		wxTreeItemId item = buf.front(); buf.pop();

		wxTreeItemIdValue cookie;
		wxTreeItemId id = GetFirstChild(item, cookie);
		if (id.IsOk()) {
			if (item != id) {
				bool finish = visitor.VisitNonleaf(item);
				if (finish) {
					break;
				}
			}

			while (id.IsOk()) {
				buf.push(id);
				id = GetNextSibling(id);
			}
		} else {
			bool finish = visitor.VisitLeaf(item);
			if (finish) {
				break;
			}
		}
	}
}

}<commit_msg>[FIXED] AddNode后置为选中<commit_after>#include "GroupTreeCtrl.h"
#include "GroupTreePanel.h"
#include "MultiSpritesImpl.h"
#include "GroupTreeImpl.h"
#include "ViewPanelMgr.h"

#include "dataset/Group.h"
#include "dataset/ISprite.h"

#include <sstream>
#include <queue>
#include <wx/menu.h>

namespace d2d
{

BEGIN_EVENT_TABLE(GroupTreeCtrl, wxTreeCtrl)
	EVT_TREE_ITEM_RIGHT_CLICK(ID_GROUP_TREE_CTRL, GroupTreeCtrl::OnItemRClick)
	EVT_TREE_ITEM_MENU(ID_GROUP_TREE_CTRL, GroupTreeCtrl::OnItemMenu)
	EVT_TREE_ITEM_ACTIVATED(ID_GROUP_TREE_CTRL, GroupTreeCtrl::OnItemActivated)
	EVT_TREE_BEGIN_DRAG(ID_GROUP_TREE_CTRL, GroupTreeCtrl::OnBeginDrag)
	EVT_TREE_END_DRAG(ID_GROUP_TREE_CTRL, GroupTreeCtrl::OnEndDrag)
	EVT_KEY_DOWN(GroupTreeCtrl::OnKeyDown)
	EVT_TREE_SEL_CHANGED(ID_GROUP_TREE_CTRL, GroupTreeCtrl::OnSelChanged)
END_EVENT_TABLE()

GroupTreeCtrl::GroupTreeCtrl(GroupTreePanel* parent, MultiSpritesImpl* sprite_impl,
							 ViewPanelMgr* view_panel_mgr)
	: wxTreeCtrl(parent, ID_GROUP_TREE_CTRL, wxDefaultPosition, wxDefaultSize,
	wxTR_EDIT_LABELS | /*wxTR_HIDE_ROOT | */wxTR_NO_LINES | wxTR_DEFAULT_STYLE)
	, m_parent_panel(parent)
	, m_sprite_impl(sprite_impl)
	, m_view_panel_mgr(view_panel_mgr)
	, m_remove_open(true)
{
	InitRoot();
}

void GroupTreeCtrl::Traverse(IGroupTreeVisitor& visitor) const
{
	Traverse(m_root, visitor);
}

wxTreeItemId GroupTreeCtrl::AddNode()
{
	static int s_num = 0;

	std::ostringstream ss;
	ss << "GROUP_" << s_num++;
	std::string text = ss.str();

	return AddNode(text);
}

wxTreeItemId GroupTreeCtrl::AddNode(const std::string& name)
{
	GroupTreeItem* data = new GroupTreeItem(new Group(name));

	wxTreeItemId ret;
	wxTreeItemId id = GetFocusedItem();
	if (id.IsOk()) {
		data->SetId(id);
		ret = AddNode(id, name, data);
	} else {
		data->SetId(m_root);
		ret = AddNode(m_root, name, data);
	}
	SetItemBold(ret, true);
	SelectItem(ret);
	return ret;
}

wxTreeItemId GroupTreeCtrl::AddNode(const std::string& name, wxTreeItemId parent)
{
	GroupTreeItem* data = new GroupTreeItem(new Group(name));
	wxTreeItemId ret = AddNode(parent, name, data);
	SetItemBold(ret, true);
	SelectItem(ret);
	return ret;
}

void GroupTreeCtrl::DelNode()
{
	wxTreeItemId id = GetFocusedItem();
	if (id.IsOk()) {
		Delete(id);
	}
}

wxTreeItemId GroupTreeCtrl::AddSprite(wxTreeItemId parent, d2d::ISprite* spr)
{
	if (!parent.IsOk()) {
		return m_root;
	}

	GroupTreeItem* data = (GroupTreeItem*)GetItemData(parent);
	if (!data) {
		return m_root;
	}

	Group* group = data->m_group;
	if (!group) {
		return m_root;
	}

	bool ok = group->Insert(spr);
	if (ok) {
		GroupTreeItem* data = new GroupTreeItem(spr);
		return AddNode(parent, spr->name, data);
	} else {
		return m_root;
	}
}

wxTreeItemId GroupTreeCtrl::AddSprite(d2d::ISprite* spr)
{
	wxTreeItemId ret;
	if (m_selected_item.IsOk()) {
		ret = AddSprite(m_selected_item, spr);
	}
	if (!ret.IsOk() || ret == m_root) {
		assert(m_root.IsOk());
		ret = AddSprite(m_root, spr);
	}
	return ret;
}

void GroupTreeCtrl::Clear()
{
	if (!IsEmpty()) {
		CollapseAndReset(m_root);
	}
}

void GroupTreeCtrl::Remove(ISprite* sprite)
{
	if (m_remove_open) {
		Traverse(GroupTreeImpl::RemoveVisitor(this, sprite));
	}
}

void GroupTreeCtrl::Visible(wxTreeItemId id, bool visible)
{
	Traverse(id, GroupTreeImpl::SetVisibleVisitor(this, visible));
}

void GroupTreeCtrl::Editable(wxTreeItemId id, bool editable)
{
	Traverse(id, GroupTreeImpl::SetEditableVisitor(this, editable));
}

void GroupTreeCtrl::ReorderItem(wxTreeItemId id, bool up)
{
	if (!id.IsOk()) {
		return;
	}

	wxTreeItemId insert_prev;
	if (up) {
		wxTreeItemId prev = GetPrevSibling(id);
		if (!prev.IsOk()) {
			return;
		}
		insert_prev = GetPrevSibling(prev);
	} else {
		wxTreeItemId next = GetNextSibling(id);
		if (!next.IsOk()) {
			return;
		}
		insert_prev = next;
	}

	// old info
	GroupTreeItem* data = (GroupTreeItem*)GetItemData(id);
	std::string name = GetItemText(id);

	// insert
	wxTreeItemId parent = GetItemParent(id);
	wxTreeItemId new_item;
	if (insert_prev.IsOk()) {
		new_item = InsertItem(parent, insert_prev, name, -1, -1, data->Clone());
	} else {
		new_item = InsertItem(parent, 0, name, -1, -1, data->Clone());
	}
	ExpandAll();
	// copy older's children
	Traverse(id, GroupTreeImpl::CopyPasteVisitor(this, id, new_item));
	// remove
	Delete(id);
	// sort
	ReorderSprites();
	// set selection
	SelectItem(new_item);
}

wxTreeItemId GroupTreeCtrl::AddNode(wxTreeItemId parent, const std::string& name, GroupTreeItem* data)
{
	wxTreeItemId id = InsertItem(parent, 0, name, -1, -1, data);
	ExpandAll();
	return id;
}

void GroupTreeCtrl::InitRoot()
{
	GroupTreeItem* data = new GroupTreeItem(new Group("ROOT"));
	m_root = AddRoot("ROOT");
	SetItemBold(m_root, true);
	SetItemData(m_root, data);
}

void GroupTreeCtrl::OnItemRClick(wxTreeEvent& event)
{
	wxTreeItemId itemId = event.GetItem();

	GroupTreeItem* item = (GroupTreeItem*)GetItemData(itemId);

	event.Skip();
}

void GroupTreeCtrl::OnItemMenu(wxTreeEvent& event)
{
	wxTreeItemId id = event.GetItem();
	if (!id.IsOk()) {
		return;
	}

	wxPoint clientpt = event.GetPoint();
	wxPoint screenpt = ClientToScreen(clientpt);
	ShowMenu(id, clientpt);
	event.Skip();
}

void GroupTreeCtrl::OnItemActivated(wxTreeEvent& event)
{
	wxTreeItemId id = event.GetItem();
	SpriteSelection* selection = m_sprite_impl->getSpriteSelection();
	selection->Clear();
	Traverse(id, GroupTreeImpl::SelectVisitor(this, selection));
}

void GroupTreeCtrl::OnBeginDrag(wxTreeEvent& event)
{
	m_dragged_item = event.GetItem();
	event.Allow();
}

void GroupTreeCtrl::OnEndDrag(wxTreeEvent& event)
{
	wxTreeItemId item_src = m_dragged_item,
		item_dst = event.GetItem();
	if (!item_dst.IsOk()) {
		return;
	}

	wxLogDebug("Drag from %s to %s", GetItemText(item_src), GetItemText(item_dst));

	// old info
	GroupTreeItem* data = (GroupTreeItem*)GetItemData(item_src);
	std::string name = GetItemText(item_src);
	// insert
	wxTreeItemId new_item = InsertItem(item_dst, 0, name, -1, -1, data->Clone());
	ExpandAll();
	// copy older's children
	Traverse(item_src, GroupTreeImpl::CopyPasteVisitor(this, item_src, new_item));
	// remove
	Delete(item_src);
	// sort
	ReorderSprites();
}

void GroupTreeCtrl::OnKeyDown(wxKeyEvent& event)
{
	switch (event.GetKeyCode())
	{
	case WXK_UP:
		SelectUp();
		break;
	case WXK_DOWN:
		SelectDown();
		break;
	case WXK_LEFT:
		SelectLeft();
		break;
	case WXK_RIGHT:
		SelectRight();
		break;
	case WXK_PAGEUP:
		ReorderItem(m_selected_item, true);
		break;
	case WXK_PAGEDOWN:
		ReorderItem(m_selected_item, false);
		break;
	}
}

void GroupTreeCtrl::OnSelChanged(wxTreeEvent& event)
{
	m_selected_item = event.GetItem();

	wxLogDebug("OnSelChanged %s", GetItemText(m_selected_item));

	GroupTreeItem* data = (GroupTreeItem*)GetItemData(m_selected_item);
	if (data && data->m_sprite) {
		m_view_panel_mgr->SelectSprite(data->m_sprite, m_parent_panel);
	}
}

void GroupTreeCtrl::OnMenuAddSprites(wxCommandEvent& event)
{
	if (!m_on_menu_id.IsOk()) {
		return;
	}

	GroupTreeItem* data = (GroupTreeItem*)GetItemData(m_on_menu_id);
	if (!data) {
		return;
	}

	Group* group = data->m_group;
	if (!group) {
		return;
	}

	SpriteSelection* selection = m_sprite_impl->getSpriteSelection();
	std::vector<ISprite*> sprites;
	selection->Traverse(FetchAllVisitor<ISprite>(sprites));
	for (int i = 0, n = sprites.size(); i < n; ++i) {
		ISprite* spr = sprites[i];
		bool ok = group->Insert(spr);
		if (ok) {
			GroupTreeItem* data = new GroupTreeItem(spr);
			AddNode(m_on_menu_id, spr->name, data);
		}
	}
}

void GroupTreeCtrl::OnMenuClear(wxCommandEvent& event)
{
	if (!m_on_menu_id.IsOk()) {
		return;
	}

	Group* group = ((GroupTreeItem*)GetItemData(m_on_menu_id))->m_group;
	if (!group) {
		return;
	}

	group->Clear();
	CollapseAndReset(m_on_menu_id);
}

void GroupTreeCtrl::OnMenuVisible(wxCommandEvent& event)
{
	Traverse(m_on_menu_id, GroupTreeImpl::VisibleVisitor(this));
}

void GroupTreeCtrl::OnMenuEditable(wxCommandEvent& event)
{
	Traverse(m_on_menu_id, GroupTreeImpl::EditableVisitor(this));
}

void GroupTreeCtrl::SelectUp()
{
	if (!m_selected_item.IsOk()) {
		return;
	}

	wxTreeItemId prev = GetPrevSibling(m_selected_item);
	if (prev.IsOk()) {
		SelectItem(prev);
	}
}

void GroupTreeCtrl::SelectDown()
{
	if (!m_selected_item.IsOk()) {
		return;
	}

	wxTreeItemId next = GetNextSibling(m_selected_item);
	if (next.IsOk()) {
		SelectItem(next);
	}
}

void GroupTreeCtrl::SelectLeft()
{
	if (!m_selected_item.IsOk()) {
		return;
	}

	if (ItemHasChildren(m_selected_item) && IsExpanded(m_selected_item)) {
		Collapse(m_selected_item);
	} else {
	 	wxTreeItemId parent = GetItemParent(m_selected_item);
	 	if (parent.IsOk() && parent != m_root) {
	 		SelectItem(parent);
	 	}
	}
}

void GroupTreeCtrl::SelectRight()
{
	if (!m_selected_item.IsOk()) {
		return;
	}

	if (ItemHasChildren(m_selected_item)) {
		if (IsExpanded(m_selected_item)) {
			wxTreeItemIdValue cookie;
			wxTreeItemId next = GetFirstChild(m_selected_item, cookie);
			if (next.IsOk()) {
				SelectItem(next);
			}
		} else {
			Expand(m_selected_item);
		}
	}
}

void GroupTreeCtrl::ReorderSprites()
{
	std::vector<ISprite*> sprites;
	Traverse(m_root, GroupTreeImpl::GetSpritesVisitor(this, sprites));
	for (int i = sprites.size() - 1; i >= 0; --i) {
		ISprite* spr = sprites[i];
		m_remove_open = false;
		m_sprite_impl->removeSprite(spr);
		m_remove_open = true;
		m_sprite_impl->insertSprite(spr);
	}
}

void GroupTreeCtrl::ShowMenu(wxTreeItemId id, const wxPoint& pt)
{
	m_on_menu_id = id;

	wxMenu menu;

	menu.Append(ID_MENU_ADD, wxT("&Add Sprites"));
	Bind(wxEVT_COMMAND_MENU_SELECTED, &GroupTreeCtrl::OnMenuAddSprites, this, ID_MENU_ADD);

	menu.Append(ID_MENU_CLEAR, wxT("&Clear Sprites"));
	Bind(wxEVT_COMMAND_MENU_SELECTED, &GroupTreeCtrl::OnMenuClear, this, ID_MENU_CLEAR);

	menu.AppendSeparator();

	menu.AppendCheckItem(ID_MENU_VISIBLE, wxT("&Visible"));
	Bind(wxEVT_COMMAND_MENU_SELECTED, &GroupTreeCtrl::OnMenuVisible, this, ID_MENU_VISIBLE);

	menu.AppendCheckItem(ID_MENU_EDITABLE, wxT("&Editable"));
	Bind(wxEVT_COMMAND_MENU_SELECTED, &GroupTreeCtrl::OnMenuEditable, this, ID_MENU_EDITABLE);

	PopupMenu(&menu, pt);
}

void GroupTreeCtrl::Traverse(wxTreeItemId id, IGroupTreeVisitor& visitor) const
{
	std::queue<wxTreeItemId> buf;
	buf.push(id);
	while (!buf.empty()) {
		wxTreeItemId item = buf.front(); buf.pop();

		wxTreeItemIdValue cookie;
		wxTreeItemId id = GetFirstChild(item, cookie);
		if (id.IsOk()) {
			if (item != id) {
				bool finish = visitor.VisitNonleaf(item);
				if (finish) {
					break;
				}
			}

			while (id.IsOk()) {
				buf.push(id);
				id = GetNextSibling(id);
			}
		} else {
			bool finish = visitor.VisitLeaf(item);
			if (finish) {
				break;
			}
		}
	}
}

}<|endoftext|>


<commit_before>#ifndef MAPNIK_VECTOR_TILE_STRATEGY_HPP
#define MAPNIK_VECTOR_TILE_STRATEGY_HPP

// mapnik
#include <mapnik/config.hpp>
#include <mapnik/util/noncopyable.hpp>
#include <mapnik/proj_transform.hpp>
#include <mapnik/view_transform.hpp>
#include <mapnik/geometry_envelope.hpp>

#include "clipper.hpp"

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#pragma GCC diagnostic ignored "-Wunused-local-typedef"
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/numeric/conversion/cast.hpp>
#pragma GCC diagnostic pop

namespace mapnik {

namespace vector_tile_impl {

static constexpr double coord_max = static_cast<double>(ClipperLib::hiRange);
static constexpr double coord_min = -1 * static_cast<double>(ClipperLib::hiRange);

struct vector_tile_strategy
{
    vector_tile_strategy(view_transform const& tr,
                          double scaling)
        : tr_(tr),
          scaling_(scaling) {}

    template <typename P1, typename P2>
    inline bool apply(P1 const& p1, P2 & p2) const
    {
        using p2_type = typename boost::geometry::coordinate_type<P2>::type;
        double x = boost::geometry::get<0>(p1);
        double y = boost::geometry::get<1>(p1);
        tr_.forward(&x,&y);
        x = std::round(x * scaling_);
        y = std::round(y * scaling_);
        if (x <= coord_min || x >= coord_max ||
            y <= coord_min || y >= coord_max) return false;
        boost::geometry::set<0>(p2, static_cast<p2_type>(x));
        boost::geometry::set<1>(p2, static_cast<p2_type>(y));
        return true;
    }

    template <typename P1, typename P2>
    inline P2 execute(P1 const& p1, bool & status) const
    {
        P2 p2;
        status = apply(p1, p2);
        return p2;
    }

    view_transform const& tr_;
    double const scaling_;
};

struct vector_tile_strategy_proj
{
    vector_tile_strategy_proj(proj_transform const& prj_trans,
                         view_transform const& tr,
                         double scaling)
        : prj_trans_(prj_trans),
          tr_(tr),
          scaling_(scaling),
          not_equal_(!prj_trans_.equal()) {}

    template <typename P1, typename P2>
    inline bool apply(P1 const& p1, P2 & p2) const
    {
        using p2_type = typename boost::geometry::coordinate_type<P2>::type;
        double x = boost::geometry::get<0>(p1);
        double y = boost::geometry::get<1>(p1);
        double z = 0.0;
        if (not_equal_ && !prj_trans_.backward(x, y, z)) return false;
        tr_.forward(&x,&y);
        x = std::round(x * scaling_);
        y = std::round(y * scaling_);
        if (x <= coord_min || x >= coord_max ||
            y <= coord_min || y >= coord_max) return false;
        boost::geometry::set<0>(p2, static_cast<p2_type>(x));
        boost::geometry::set<1>(p2, static_cast<p2_type>(y));
        return true;
    }

    template <typename P1, typename P2>
    inline P2 execute(P1 const& p1, bool & status) const
    {
        P2 p2;
        status = apply(p1, p2);
        return p2;
    }

    proj_transform const& prj_trans_;
    view_transform const& tr_;
    double const scaling_;
    bool not_equal_;
};

// TODO - avoid creating degenerate polygons when first/last point of ring is skipped
template <typename TransformType>
struct transform_visitor {

    transform_visitor(TransformType const& tr, box2d<double> const& target_clipping_extent) :
      tr_(tr),
      target_clipping_extent_(target_clipping_extent) {}

    inline mapnik::geometry::geometry<std::int64_t> operator() (mapnik::geometry::point<double> const& geom)
    {
        if (!target_clipping_extent_.intersects(geom.x,geom.y)) return mapnik::geometry::geometry_empty();
        mapnik::geometry::point<std::int64_t> new_geom;
        if (!tr_.apply(geom,new_geom)) return mapnik::geometry::geometry_empty();
        return new_geom;
    }

    inline mapnik::geometry::geometry<std::int64_t> operator() (mapnik::geometry::multi_point<double> const& geom)
    {
        mapnik::geometry::multi_point<std::int64_t> new_geom;
        new_geom.reserve(geom.size());
        for (auto const& pt : geom)
        {
            mapnik::geometry::point<std::int64_t> pt2;
            if (target_clipping_extent_.intersects(pt.x, pt.y) && tr_.apply(pt,pt2))
            {
                new_geom.push_back(std::move(pt2));
            }
        }
        if (new_geom.empty()) return mapnik::geometry::geometry_empty();
        new_geom.shrink_to_fit();
        return new_geom;
    }

    inline mapnik::geometry::geometry<std::int64_t> operator() (mapnik::geometry::line_string<double> const& geom)
    {
        mapnik::box2d<double> geom_bbox = mapnik::geometry::envelope(geom);
        if (!target_clipping_extent_.intersects(geom_bbox))
        {
            return mapnik::geometry::geometry_empty();
        }
        mapnik::geometry::line_string<std::int64_t> new_geom;
        new_geom.reserve(geom.size());
        for (auto const& pt : geom)
        {
            mapnik::geometry::point<std::int64_t> pt2;
            if (tr_.apply(pt,pt2))
            {
                new_geom.push_back(std::move(pt2));
            }
        }
        return new_geom;
    }

    inline mapnik::geometry::geometry<std::int64_t> operator() (mapnik::geometry::multi_line_string<double> const& geom)
    {
        mapnik::geometry::multi_line_string<std::int64_t> new_geom;
        new_geom.reserve(geom.size());
        for (auto const& line : geom)
        {
            mapnik::box2d<double> line_bbox = mapnik::geometry::envelope(line);
            if (!target_clipping_extent_.intersects(line_bbox)) continue;
            mapnik::geometry::line_string<std::int64_t> new_line;
            new_line.reserve(line.size());
            for (auto const& pt : line)
            {
                mapnik::geometry::point<std::int64_t> pt2;
                if (tr_.apply(pt,pt2))
                {
                    new_line.push_back(std::move(pt2));
                }
            }
            new_geom.push_back(std::move(new_line));
        }
        if (new_geom.empty()) return mapnik::geometry::geometry_empty();
        new_geom.shrink_to_fit();
        return new_geom;
    }

    inline mapnik::geometry::geometry<std::int64_t> operator() (mapnik::geometry::polygon<double> const& geom)
    {
        mapnik::box2d<double> ext_bbox = mapnik::geometry::envelope(geom);
        if (!target_clipping_extent_.intersects(ext_bbox))
        {
            return mapnik::geometry::geometry_empty();
        }
        mapnik::geometry::polygon<std::int64_t> new_geom;
        new_geom.exterior_ring.reserve(geom.exterior_ring.size());
        for (auto const& pt : geom.exterior_ring)
        {
            mapnik::geometry::point<std::int64_t> pt2;
            if (tr_.apply(pt,pt2))
            {
                new_geom.exterior_ring.push_back(std::move(pt2));
            }
        }
        for (auto const& ring : geom.interior_rings)
        {
            mapnik::box2d<double> ring_bbox = mapnik::geometry::envelope(static_cast<mapnik::geometry::line_string<double> const&>(ring));
            if (!target_clipping_extent_.intersects(ring_bbox))
            {
                continue;
            }
            mapnik::geometry::linear_ring<std::int64_t> new_ring;
            new_ring.reserve(ring.size());
            for (auto const& pt : ring)
            {
                mapnik::geometry::point<std::int64_t> pt2;
                if (tr_.apply(pt,pt2))
                {
                    new_ring.push_back(std::move(pt2));
                }
            }
            new_geom.interior_rings.push_back(std::move(new_ring));
        }
        return new_geom;
    }

    inline mapnik::geometry::geometry<std::int64_t> operator() (mapnik::geometry::multi_polygon<double> const& geom)
    {
        mapnik::geometry::multi_polygon<std::int64_t> new_geom;
        new_geom.reserve(geom.size());
        for (auto const& poly : geom)
        {
            mapnik::box2d<double> ext_bbox = mapnik::geometry::envelope(poly);
            if (!target_clipping_extent_.intersects(ext_bbox))
            {
                continue;
            }
            mapnik::geometry::polygon<std::int64_t> new_poly;
            new_poly.exterior_ring.reserve(poly.exterior_ring.size());
            for (auto const& pt : poly.exterior_ring)
            {
                mapnik::geometry::point<std::int64_t> pt2;
                if (tr_.apply(pt,pt2))
                {
                    new_poly.exterior_ring.push_back(std::move(pt2));
                }
            }
            for (auto const& ring : poly.interior_rings)
            {
                mapnik::box2d<double> ring_bbox = mapnik::geometry::envelope(static_cast<mapnik::geometry::line_string<double> const&>(ring));
                if (!target_clipping_extent_.intersects(ring_bbox))
                {
                    continue;
                }
                mapnik::geometry::linear_ring<std::int64_t> new_ring;
                new_ring.reserve(ring.size());
                for (auto const& pt : ring)
                {
                    mapnik::geometry::point<std::int64_t> pt2;
                    if (tr_.apply(pt,pt2))
                    {
                        new_ring.push_back(std::move(pt2));
                    }
                }
                new_poly.interior_rings.push_back(std::move(new_ring));
            }
            new_geom.push_back(std::move(new_poly));
        }
        if (new_geom.empty()) return mapnik::geometry::geometry_empty();
        new_geom.shrink_to_fit();
        return new_geom;
    }

    inline mapnik::geometry::geometry<std::int64_t> operator() (mapnik::geometry::geometry_collection<double> const& geom)
    {
        mapnik::geometry::geometry_collection<std::int64_t> new_geom;
        new_geom.reserve(geom.size());
        for (auto const& g : geom)
        {
            new_geom.push_back(mapnik::util::apply_visitor((*this), g));
        }
        return new_geom;
     }

    inline mapnik::geometry::geometry<std::int64_t> operator() (mapnik::geometry::geometry_empty const& geom)
    {
        return geom;
    }
    TransformType const& tr_;
    box2d<double> const& target_clipping_extent_;
};

}
}

#endif // MAPNIK_VECTOR_TILE_STRATEGY_HPP
<commit_msg>remove shrink_to_fix - refs mapnik/mapnik#2984<commit_after>#ifndef MAPNIK_VECTOR_TILE_STRATEGY_HPP
#define MAPNIK_VECTOR_TILE_STRATEGY_HPP

// mapnik
#include <mapnik/config.hpp>
#include <mapnik/util/noncopyable.hpp>
#include <mapnik/proj_transform.hpp>
#include <mapnik/view_transform.hpp>
#include <mapnik/geometry_envelope.hpp>

#include "clipper.hpp"

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#pragma GCC diagnostic ignored "-Wunused-local-typedef"
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/numeric/conversion/cast.hpp>
#pragma GCC diagnostic pop

namespace mapnik {

namespace vector_tile_impl {

static constexpr double coord_max = static_cast<double>(ClipperLib::hiRange);
static constexpr double coord_min = -1 * static_cast<double>(ClipperLib::hiRange);

struct vector_tile_strategy
{
    vector_tile_strategy(view_transform const& tr,
                          double scaling)
        : tr_(tr),
          scaling_(scaling) {}

    template <typename P1, typename P2>
    inline bool apply(P1 const& p1, P2 & p2) const
    {
        using p2_type = typename boost::geometry::coordinate_type<P2>::type;
        double x = boost::geometry::get<0>(p1);
        double y = boost::geometry::get<1>(p1);
        tr_.forward(&x,&y);
        x = std::round(x * scaling_);
        y = std::round(y * scaling_);
        if (x <= coord_min || x >= coord_max ||
            y <= coord_min || y >= coord_max) return false;
        boost::geometry::set<0>(p2, static_cast<p2_type>(x));
        boost::geometry::set<1>(p2, static_cast<p2_type>(y));
        return true;
    }

    template <typename P1, typename P2>
    inline P2 execute(P1 const& p1, bool & status) const
    {
        P2 p2;
        status = apply(p1, p2);
        return p2;
    }

    view_transform const& tr_;
    double const scaling_;
};

struct vector_tile_strategy_proj
{
    vector_tile_strategy_proj(proj_transform const& prj_trans,
                         view_transform const& tr,
                         double scaling)
        : prj_trans_(prj_trans),
          tr_(tr),
          scaling_(scaling),
          not_equal_(!prj_trans_.equal()) {}

    template <typename P1, typename P2>
    inline bool apply(P1 const& p1, P2 & p2) const
    {
        using p2_type = typename boost::geometry::coordinate_type<P2>::type;
        double x = boost::geometry::get<0>(p1);
        double y = boost::geometry::get<1>(p1);
        double z = 0.0;
        if (not_equal_ && !prj_trans_.backward(x, y, z)) return false;
        tr_.forward(&x,&y);
        x = std::round(x * scaling_);
        y = std::round(y * scaling_);
        if (x <= coord_min || x >= coord_max ||
            y <= coord_min || y >= coord_max) return false;
        boost::geometry::set<0>(p2, static_cast<p2_type>(x));
        boost::geometry::set<1>(p2, static_cast<p2_type>(y));
        return true;
    }

    template <typename P1, typename P2>
    inline P2 execute(P1 const& p1, bool & status) const
    {
        P2 p2;
        status = apply(p1, p2);
        return p2;
    }

    proj_transform const& prj_trans_;
    view_transform const& tr_;
    double const scaling_;
    bool not_equal_;
};

// TODO - avoid creating degenerate polygons when first/last point of ring is skipped
template <typename TransformType>
struct transform_visitor {

    transform_visitor(TransformType const& tr, box2d<double> const& target_clipping_extent) :
      tr_(tr),
      target_clipping_extent_(target_clipping_extent) {}

    inline mapnik::geometry::geometry<std::int64_t> operator() (mapnik::geometry::point<double> const& geom)
    {
        if (!target_clipping_extent_.intersects(geom.x,geom.y)) return mapnik::geometry::geometry_empty();
        mapnik::geometry::point<std::int64_t> new_geom;
        if (!tr_.apply(geom,new_geom)) return mapnik::geometry::geometry_empty();
        return new_geom;
    }

    inline mapnik::geometry::geometry<std::int64_t> operator() (mapnik::geometry::multi_point<double> const& geom)
    {
        mapnik::geometry::multi_point<std::int64_t> new_geom;
        new_geom.reserve(geom.size());
        for (auto const& pt : geom)
        {
            mapnik::geometry::point<std::int64_t> pt2;
            if (target_clipping_extent_.intersects(pt.x, pt.y) && tr_.apply(pt,pt2))
            {
                new_geom.push_back(std::move(pt2));
            }
        }
        if (new_geom.empty()) return mapnik::geometry::geometry_empty();
        return new_geom;
    }

    inline mapnik::geometry::geometry<std::int64_t> operator() (mapnik::geometry::line_string<double> const& geom)
    {
        mapnik::box2d<double> geom_bbox = mapnik::geometry::envelope(geom);
        if (!target_clipping_extent_.intersects(geom_bbox))
        {
            return mapnik::geometry::geometry_empty();
        }
        mapnik::geometry::line_string<std::int64_t> new_geom;
        new_geom.reserve(geom.size());
        for (auto const& pt : geom)
        {
            mapnik::geometry::point<std::int64_t> pt2;
            if (tr_.apply(pt,pt2))
            {
                new_geom.push_back(std::move(pt2));
            }
        }
        return new_geom;
    }

    inline mapnik::geometry::geometry<std::int64_t> operator() (mapnik::geometry::multi_line_string<double> const& geom)
    {
        mapnik::geometry::multi_line_string<std::int64_t> new_geom;
        new_geom.reserve(geom.size());
        for (auto const& line : geom)
        {
            mapnik::box2d<double> line_bbox = mapnik::geometry::envelope(line);
            if (!target_clipping_extent_.intersects(line_bbox)) continue;
            mapnik::geometry::line_string<std::int64_t> new_line;
            new_line.reserve(line.size());
            for (auto const& pt : line)
            {
                mapnik::geometry::point<std::int64_t> pt2;
                if (tr_.apply(pt,pt2))
                {
                    new_line.push_back(std::move(pt2));
                }
            }
            new_geom.push_back(std::move(new_line));
        }
        if (new_geom.empty()) return mapnik::geometry::geometry_empty();
        return new_geom;
    }

    inline mapnik::geometry::geometry<std::int64_t> operator() (mapnik::geometry::polygon<double> const& geom)
    {
        mapnik::box2d<double> ext_bbox = mapnik::geometry::envelope(geom);
        if (!target_clipping_extent_.intersects(ext_bbox))
        {
            return mapnik::geometry::geometry_empty();
        }
        mapnik::geometry::polygon<std::int64_t> new_geom;
        new_geom.exterior_ring.reserve(geom.exterior_ring.size());
        for (auto const& pt : geom.exterior_ring)
        {
            mapnik::geometry::point<std::int64_t> pt2;
            if (tr_.apply(pt,pt2))
            {
                new_geom.exterior_ring.push_back(std::move(pt2));
            }
        }
        for (auto const& ring : geom.interior_rings)
        {
            mapnik::box2d<double> ring_bbox = mapnik::geometry::envelope(static_cast<mapnik::geometry::line_string<double> const&>(ring));
            if (!target_clipping_extent_.intersects(ring_bbox))
            {
                continue;
            }
            mapnik::geometry::linear_ring<std::int64_t> new_ring;
            new_ring.reserve(ring.size());
            for (auto const& pt : ring)
            {
                mapnik::geometry::point<std::int64_t> pt2;
                if (tr_.apply(pt,pt2))
                {
                    new_ring.push_back(std::move(pt2));
                }
            }
            new_geom.interior_rings.push_back(std::move(new_ring));
        }
        return new_geom;
    }

    inline mapnik::geometry::geometry<std::int64_t> operator() (mapnik::geometry::multi_polygon<double> const& geom)
    {
        mapnik::geometry::multi_polygon<std::int64_t> new_geom;
        new_geom.reserve(geom.size());
        for (auto const& poly : geom)
        {
            mapnik::box2d<double> ext_bbox = mapnik::geometry::envelope(poly);
            if (!target_clipping_extent_.intersects(ext_bbox))
            {
                continue;
            }
            mapnik::geometry::polygon<std::int64_t> new_poly;
            new_poly.exterior_ring.reserve(poly.exterior_ring.size());
            for (auto const& pt : poly.exterior_ring)
            {
                mapnik::geometry::point<std::int64_t> pt2;
                if (tr_.apply(pt,pt2))
                {
                    new_poly.exterior_ring.push_back(std::move(pt2));
                }
            }
            for (auto const& ring : poly.interior_rings)
            {
                mapnik::box2d<double> ring_bbox = mapnik::geometry::envelope(static_cast<mapnik::geometry::line_string<double> const&>(ring));
                if (!target_clipping_extent_.intersects(ring_bbox))
                {
                    continue;
                }
                mapnik::geometry::linear_ring<std::int64_t> new_ring;
                new_ring.reserve(ring.size());
                for (auto const& pt : ring)
                {
                    mapnik::geometry::point<std::int64_t> pt2;
                    if (tr_.apply(pt,pt2))
                    {
                        new_ring.push_back(std::move(pt2));
                    }
                }
                new_poly.interior_rings.push_back(std::move(new_ring));
            }
            new_geom.push_back(std::move(new_poly));
        }
        if (new_geom.empty()) return mapnik::geometry::geometry_empty();
        return new_geom;
    }

    inline mapnik::geometry::geometry<std::int64_t> operator() (mapnik::geometry::geometry_collection<double> const& geom)
    {
        mapnik::geometry::geometry_collection<std::int64_t> new_geom;
        new_geom.reserve(geom.size());
        for (auto const& g : geom)
        {
            new_geom.push_back(mapnik::util::apply_visitor((*this), g));
        }
        return new_geom;
     }

    inline mapnik::geometry::geometry<std::int64_t> operator() (mapnik::geometry::geometry_empty const& geom)
    {
        return geom;
    }
    TransformType const& tr_;
    box2d<double> const& target_clipping_extent_;
};

}
}

#endif // MAPNIK_VECTOR_TILE_STRATEGY_HPP
<|endoftext|>


<commit_before><commit_msg>Initialize an empty password for NSS databases (so that the databases won't require login) if the password hasn't been initialized yet.<commit_after><|endoftext|>