<commit_before>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// version: $Id$
// author:  Axel Naumann <axel@cern.ch>
//------------------------------------------------------------------------------

#include "cling/MetaProcessor/MetaProcessor.h"

#include "InputValidator.h"
#include "cling/Interpreter/Interpreter.h"

#include "clang/Basic/FileManager.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Lex/Preprocessor.h"

#include "llvm/Support/Path.h"

using namespace clang;

namespace cling {

  MetaProcessor::MetaProcessor(Interpreter& interp) : m_Interp(interp) {
    m_InputValidator.reset(new InputValidator());
  }

  MetaProcessor::~MetaProcessor() {}

  int MetaProcessor::process(const char* input_text, Value* result /*=0*/) {
    if (!input_text) { // null pointer, nothing to do.
      return 0;
    }
    if (!input_text[0]) { // empty string, nothing to do.
      return m_InputValidator->getExpectedIndent();
    }
    std::string input_line(input_text);
    if (input_line == "\n") { // just a blank line, nothing to do.
      return 0;
    }
    //  Check for and handle any '.' commands.
    bool was_meta = false;
    if ((input_line[0] == '.') && (input_line.size() > 1)) {
      was_meta = ProcessMeta(input_line, result);
    }
    if (was_meta) {
      return 0;
    }

    // Check if the current statement is now complete. If not, return to
    // prompt for more.
    if (m_InputValidator->Validate(input_line, m_Interp.getCI()->getLangOpts())
        == InputValidator::kIncomplete) {
      return m_InputValidator->getExpectedIndent();
    }

    //  We have a complete statement, compile and execute it.
    std::string input = m_InputValidator->TakeInput();
    m_InputValidator->Reset();
    m_Interp.processLine(input, m_Options.RawInput, result);

    return 0;
  }

  MetaProcessorOpts& MetaProcessor::getMetaProcessorOpts() {
    // Take interpreter's state
    m_Options.PrintingAST = m_Interp.isPrintingAST();
    return m_Options;
  }

  bool MetaProcessor::ProcessMeta(const std::string& input_line, Value* result){

   llvm::MemoryBuffer* MB = llvm::MemoryBuffer::getMemBuffer(input_line);
   LangOptions LO;
   LO.C99 = 1;
   // necessary for the @ symbol
   LO.ObjC1 = 1;
   Lexer RawLexer(SourceLocation(), LO, MB->getBufferStart(),
                  MB->getBufferStart(), MB->getBufferEnd());
   Token Tok;

   RawLexer.LexFromRawLexer(Tok);
   if (Tok.isNot(tok::period))
     return false;

   // Read the command
   RawLexer.LexFromRawLexer(Tok);
   if (!Tok.isAnyIdentifier() && Tok.isNot(tok::at))
     return false;

   const std::string Command = GetRawTokenName(Tok);
   std::string Param;

   //  .q //Quits
   if (Command == "q") {
      m_Options.Quitting = true;
      return true;
   }
   //  .L <filename>   //  Load code fragment.
   else if (Command == "L") {
     // TODO: Additional checks on params
     bool success
       = m_Interp.loadFile(SanitizeArg(ReadToEndOfBuffer(RawLexer, MB)));
     if (!success) {
       llvm::errs() << "Load file failed.\n";
     }
     return true;
   }
   //  .(x|X) <filename> //  Execute function from file, function name is
   //                    //  filename without extension.
   else if ((Command == "x") || (Command == "X")) {
     // TODO: Additional checks on params
     llvm::sys::Path path(SanitizeArg(ReadToEndOfBuffer(RawLexer, MB)));

     if (!path.isValid())
       return false;

     bool success = executeFile(path.c_str(), result);
      if (!success) {
        llvm::errs()<< "Execute file failed.\n";
      }
      return true;
   }
   //  .printAST [0|1]  // Toggle the printing of the AST or if 1 or 0 is given
   //                   // enable or disable it.
   else if (Command == "printAST") {
     // Check for params
     RawLexer.LexFromRawLexer(Tok);
     if (Tok.isNot(tok::numeric_constant) && Tok.isNot(tok::eof))
       return false;

     if (Tok.is(tok::eof)) {
       // toggle:
       bool print = !m_Interp.isPrintingAST();
       m_Interp.enablePrintAST(print);
       llvm::errs()<< (print?"P":"Not p") << "rinting AST\n";
     } else {
       Param = GetRawTokenName(Tok);

       if (Param == "0")
         m_Interp.enablePrintAST(false);
       else
         m_Interp.enablePrintAST(true);
     }

     m_Options.PrintingAST = m_Interp.isPrintingAST();
     return true;
   }
   //  .rawInput [0|1]  // Toggle the raw input or if 1 or 0 is given enable
   //                   // or disable it.
   else if (Command == "rawInput") {
     // Check for params
     RawLexer.LexFromRawLexer(Tok);
     if (Tok.isNot(tok::numeric_constant) && Tok.isNot(tok::eof))
       return false;

     if (Tok.is(tok::eof)) {
       // toggle:
       m_Options.RawInput = !m_Options.RawInput;
       llvm::errs() << (m_Options.RawInput?"U":"Not u") << "sing raw input\n";
     } else {
       Param = GetRawTokenName(Tok);

       if (Param == "0")
         m_Options.RawInput = false;
       else
         m_Options.RawInput = true;
     }
     return true;
   }
   //
   //  .U <filename>
   //
   //  Unload code fragment.
   //
   //if (cmd_char == 'U') {
   //   llvm::sys::Path path(param);
   //   if (path.isDynamicLibrary()) {
   //      std::cerr << "[i] Failure: cannot unload shared libraries yet!"
   //                << std::endl;
   //   }
   //   bool success = m_Interp.unloadFile(param);
   //   if (!success) {
   //      //fprintf(stderr, "Unload file failed.\n");
   //   }
   //   return true;
   //}
   //
   //  Unrecognized command.
   //
   //fprintf(stderr, "Unrecognized command.\n");
   else if (Command == "I") {

     // Check for params
     llvm::sys::Path path(SanitizeArg(ReadToEndOfBuffer(RawLexer, MB)));

     if (path.isEmpty())
       m_Interp.DumpIncludePath();
     else {
       // TODO: Additional checks on params

       if (path.isValid())
         m_Interp.AddIncludePath(path.c_str());
       else
         return false;
     }
     return true;
   }
  // Cancel the multiline input that has been requested
   else if (Command == "@") {
     m_InputValidator->Reset();
     return true;
   }
   // Enable/Disable DynamicExprTransformer
   else if (Command == "dynamicExtensions") {
     // Check for params
     RawLexer.LexFromRawLexer(Tok);
     if (Tok.isNot(tok::numeric_constant) && Tok.isNot(tok::eof))
       return false;

     if (Tok.is(tok::eof)) {
       // toggle:
       bool dynlookup = !m_Interp.isDynamicLookupEnabled();
       m_Interp.enableDynamicLookup(dynlookup);
       llvm::errs() << (dynlookup?"U":"Not u") <<"sing dynamic extensions\n";
     } else {
       Param = GetRawTokenName(Tok);

       if (Param == "0")
         m_Interp.enableDynamicLookup(false);
       else
         m_Interp.enableDynamicLookup(true);
     }

     return true;
   }
   // Print Help
   else if (Command == "help") {
     PrintCommandHelp();
     return true;
   }
   // Print the loaded files
   else if (Command == "file") {
     PrintFileStats();
     return true;
   }

   return false;
  }

  std::string MetaProcessor::GetRawTokenName(const Token& Tok) {

    assert(!Tok.needsCleaning() && "Not implemented yet");

    switch (Tok.getKind()) {
    default:
      assert("Unknown token");
      return "";
    case tok::at:
      return "@";
    case tok::l_paren:
      return "(";
    case tok::r_paren:
      return ")";
    case tok::period:
      return ".";
    case tok::slash:
      return "/";
    case tok::numeric_constant:
      return StringRef(Tok.getLiteralData(), Tok.getLength()).str();
    case tok::raw_identifier:
      return StringRef(Tok.getRawIdentifierData(), Tok.getLength()).str();
    }
  }

  llvm::StringRef MetaProcessor::ReadToEndOfBuffer(Lexer& RawLexer,
                                                   llvm::MemoryBuffer* MB) {
    const char* CurPtr = RawLexer.getBufferLocation();
    if (CurPtr == MB->getBufferEnd()) {
      // Already at end of the buffer, return just the zero byte at the end.
      return StringRef(CurPtr, 1);
    }
    Token TmpTok;
    RawLexer.getAndAdvanceChar(CurPtr, TmpTok);
    return StringRef(CurPtr, MB->getBufferSize()-(CurPtr-MB->getBufferStart()));
  }

  llvm::StringRef MetaProcessor::SanitizeArg(const std::string& Str) {

    size_t begins = Str.find_first_not_of(" \t\n");
    size_t ends = Str.find_last_not_of(" \t\n") + 1;
    if (begins == std::string::npos)
      begins = 0;
    if (ends == std::string::npos)
      ends = Str.size();

      return Str.substr(begins, ends - begins);
  }

  void MetaProcessor::PrintCommandHelp() {
    llvm::outs() << "Cling meta commands usage\n";
    llvm::outs() << "Syntax: .Command [arg0 arg1 ... argN]\n";
    llvm::outs() << "\n";
    llvm::outs() << ".q\t\t\t\t - Exit the program\n";
    llvm::outs() << ".L <filename>\t\t\t - Load file or library\n";
    llvm::outs() << ".(x|X) <filename>[args]\t\t - Same as .L and runs a ";
    llvm::outs() << "function with signature ret_type filename(args)\n";
    llvm::outs() << ".I [path]\t\t\t - Shows the include path. If a path is ";
    llvm::outs() << "given - adds the path to the list with the include paths\n";
    llvm::outs() << ".@ \t\t\t\t - Cancels and ignores the multiline input\n";
    llvm::outs() << ".rawInput [0|1]\t\t\t - Toggles the wrapping and printing ";
    llvm::outs() << "the execution results of the input\n";
    llvm::outs() << ".dynamicExtensions [0|1]\t - Toggles the use of the ";
    llvm::outs() << "dynamic scopes and the late binding\n";
    llvm::outs() << ".printAST [0|1]\t\t\t - Toggles the printing of input's ";
    llvm::outs() << "corresponding AST nodes\n";
    llvm::outs() << ".help\t\t\t\t - Shows this information\n";
  }

  void MetaProcessor::PrintFileStats() {
    const SourceManager& SM = m_Interp.getCI()->getSourceManager();
    SM.getFileManager().PrintStats();

    llvm::outs() << "\n***\n\n";

    for (SourceManager::fileinfo_iterator I = SM.fileinfo_begin(),
           E = SM.fileinfo_end(); I != E; ++I) {
      llvm::outs() << (*I).first->getName();
      llvm::outs() << "\n";
    }

  }

  // Run a file: .x file[(args)]
  bool MetaProcessor::executeFile(const std::string& fileWithArgs,
                                  Value* result) {
    // Look for start of parameters:

    typedef std::pair<llvm::StringRef,llvm::StringRef> StringRefPair;

    StringRefPair pairFileArgs = llvm::StringRef(fileWithArgs).split('(');
    if (pairFileArgs.second.empty()) {
      pairFileArgs.second = ")";
    }
    StringRefPair pairPathFile = pairFileArgs.first.rsplit('/');
    if (pairPathFile.second.empty()) {
       pairPathFile.second = pairPathFile.first;
    }
    StringRefPair pairFuncExt = pairPathFile.second.rsplit('.');

    //fprintf(stderr, "funcname: %s\n", pairFuncExt.first.data());

    Interpreter::CompilationResult interpRes
       = m_Interp.processLine(std::string("#include \"")
                              + pairFileArgs.first.str()
                              + std::string("\""), true /*raw*/);

    if (interpRes != Interpreter::kFailure) {
       std::string expression = pairFuncExt.first.str()
          + "(" + pairFileArgs.second.str();
       interpRes = m_Interp.processLine(expression, false /*not raw*/, result);
    }

    return (interpRes != Interpreter::kFailure);
  }
} // end namespace cling

<commit_msg>Don't read invalid memory. Make valgrind happy.<commit_after>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// version: $Id$
// author:  Axel Naumann <axel@cern.ch>
//------------------------------------------------------------------------------

#include "cling/MetaProcessor/MetaProcessor.h"

#include "InputValidator.h"
#include "cling/Interpreter/Interpreter.h"

#include "clang/Basic/FileManager.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Lex/Preprocessor.h"

#include "llvm/Support/Path.h"

using namespace clang;

namespace cling {

  MetaProcessor::MetaProcessor(Interpreter& interp) : m_Interp(interp) {
    m_InputValidator.reset(new InputValidator());
  }

  MetaProcessor::~MetaProcessor() {}

  int MetaProcessor::process(const char* input_text, Value* result /*=0*/) {
    if (!input_text) { // null pointer, nothing to do.
      return 0;
    }
    if (!input_text[0]) { // empty string, nothing to do.
      return m_InputValidator->getExpectedIndent();
    }
    std::string input_line(input_text);
    if (input_line == "\n") { // just a blank line, nothing to do.
      return 0;
    }
    //  Check for and handle any '.' commands.
    bool was_meta = false;
    if ((input_line[0] == '.') && (input_line.size() > 1)) {
      was_meta = ProcessMeta(input_line, result);
    }
    if (was_meta) {
      return 0;
    }

    // Check if the current statement is now complete. If not, return to
    // prompt for more.
    if (m_InputValidator->Validate(input_line, m_Interp.getCI()->getLangOpts())
        == InputValidator::kIncomplete) {
      return m_InputValidator->getExpectedIndent();
    }

    //  We have a complete statement, compile and execute it.
    std::string input = m_InputValidator->TakeInput();
    m_InputValidator->Reset();
    m_Interp.processLine(input, m_Options.RawInput, result);

    return 0;
  }

  MetaProcessorOpts& MetaProcessor::getMetaProcessorOpts() {
    // Take interpreter's state
    m_Options.PrintingAST = m_Interp.isPrintingAST();
    return m_Options;
  }

  bool MetaProcessor::ProcessMeta(const std::string& input_line, Value* result){

   llvm::MemoryBuffer* MB = llvm::MemoryBuffer::getMemBuffer(input_line);
   LangOptions LO;
   LO.C99 = 1;
   // necessary for the @ symbol
   LO.ObjC1 = 1;
   Lexer RawLexer(SourceLocation(), LO, MB->getBufferStart(),
                  MB->getBufferStart(), MB->getBufferEnd());
   Token Tok;

   RawLexer.LexFromRawLexer(Tok);
   if (Tok.isNot(tok::period))
     return false;

   // Read the command
   RawLexer.LexFromRawLexer(Tok);
   if (!Tok.isAnyIdentifier() && Tok.isNot(tok::at))
     return false;

   const std::string Command = GetRawTokenName(Tok);
   std::string Param;

   //  .q //Quits
   if (Command == "q") {
      m_Options.Quitting = true;
      return true;
   }
   //  .L <filename>   //  Load code fragment.
   else if (Command == "L") {
     // TODO: Additional checks on params
     bool success
       = m_Interp.loadFile(SanitizeArg(ReadToEndOfBuffer(RawLexer, MB)));
     if (!success) {
       llvm::errs() << "Load file failed.\n";
     }
     return true;
   }
   //  .(x|X) <filename> //  Execute function from file, function name is
   //                    //  filename without extension.
   else if ((Command == "x") || (Command == "X")) {
     // TODO: Additional checks on params
     llvm::sys::Path path(SanitizeArg(ReadToEndOfBuffer(RawLexer, MB)));

     if (!path.isValid())
       return false;

     bool success = executeFile(path.c_str(), result);
      if (!success) {
        llvm::errs()<< "Execute file failed.\n";
      }
      return true;
   }
   //  .printAST [0|1]  // Toggle the printing of the AST or if 1 or 0 is given
   //                   // enable or disable it.
   else if (Command == "printAST") {
     // Check for params
     RawLexer.LexFromRawLexer(Tok);
     if (Tok.isNot(tok::numeric_constant) && Tok.isNot(tok::eof))
       return false;

     if (Tok.is(tok::eof)) {
       // toggle:
       bool print = !m_Interp.isPrintingAST();
       m_Interp.enablePrintAST(print);
       llvm::errs()<< (print?"P":"Not p") << "rinting AST\n";
     } else {
       Param = GetRawTokenName(Tok);

       if (Param == "0")
         m_Interp.enablePrintAST(false);
       else
         m_Interp.enablePrintAST(true);
     }

     m_Options.PrintingAST = m_Interp.isPrintingAST();
     return true;
   }
   //  .rawInput [0|1]  // Toggle the raw input or if 1 or 0 is given enable
   //                   // or disable it.
   else if (Command == "rawInput") {
     // Check for params
     RawLexer.LexFromRawLexer(Tok);
     if (Tok.isNot(tok::numeric_constant) && Tok.isNot(tok::eof))
       return false;

     if (Tok.is(tok::eof)) {
       // toggle:
       m_Options.RawInput = !m_Options.RawInput;
       llvm::errs() << (m_Options.RawInput?"U":"Not u") << "sing raw input\n";
     } else {
       Param = GetRawTokenName(Tok);

       if (Param == "0")
         m_Options.RawInput = false;
       else
         m_Options.RawInput = true;
     }
     return true;
   }
   //
   //  .U <filename>
   //
   //  Unload code fragment.
   //
   //if (cmd_char == 'U') {
   //   llvm::sys::Path path(param);
   //   if (path.isDynamicLibrary()) {
   //      std::cerr << "[i] Failure: cannot unload shared libraries yet!"
   //                << std::endl;
   //   }
   //   bool success = m_Interp.unloadFile(param);
   //   if (!success) {
   //      //fprintf(stderr, "Unload file failed.\n");
   //   }
   //   return true;
   //}
   //
   //  Unrecognized command.
   //
   //fprintf(stderr, "Unrecognized command.\n");
   else if (Command == "I") {

     // Check for params
     llvm::sys::Path path(SanitizeArg(ReadToEndOfBuffer(RawLexer, MB)));

     if (path.isEmpty())
       m_Interp.DumpIncludePath();
     else {
       // TODO: Additional checks on params

       if (path.isValid())
         m_Interp.AddIncludePath(path.c_str());
       else
         return false;
     }
     return true;
   }
  // Cancel the multiline input that has been requested
   else if (Command == "@") {
     m_InputValidator->Reset();
     return true;
   }
   // Enable/Disable DynamicExprTransformer
   else if (Command == "dynamicExtensions") {
     // Check for params
     RawLexer.LexFromRawLexer(Tok);
     if (Tok.isNot(tok::numeric_constant) && Tok.isNot(tok::eof))
       return false;

     if (Tok.is(tok::eof)) {
       // toggle:
       bool dynlookup = !m_Interp.isDynamicLookupEnabled();
       m_Interp.enableDynamicLookup(dynlookup);
       llvm::errs() << (dynlookup?"U":"Not u") <<"sing dynamic extensions\n";
     } else {
       Param = GetRawTokenName(Tok);

       if (Param == "0")
         m_Interp.enableDynamicLookup(false);
       else
         m_Interp.enableDynamicLookup(true);
     }

     return true;
   }
   // Print Help
   else if (Command == "help") {
     PrintCommandHelp();
     return true;
   }
   // Print the loaded files
   else if (Command == "file") {
     PrintFileStats();
     return true;
   }

   return false;
  }

  std::string MetaProcessor::GetRawTokenName(const Token& Tok) {

    assert(!Tok.needsCleaning() && "Not implemented yet");

    switch (Tok.getKind()) {
    default:
      assert("Unknown token");
      return "";
    case tok::at:
      return "@";
    case tok::l_paren:
      return "(";
    case tok::r_paren:
      return ")";
    case tok::period:
      return ".";
    case tok::slash:
      return "/";
    case tok::numeric_constant:
      return StringRef(Tok.getLiteralData(), Tok.getLength()).str();
    case tok::raw_identifier:
      return StringRef(Tok.getRawIdentifierData(), Tok.getLength()).str();
    }
  }

  llvm::StringRef MetaProcessor::ReadToEndOfBuffer(Lexer& RawLexer,
                                                   llvm::MemoryBuffer* MB) {
    const char* CurPtr = RawLexer.getBufferLocation();
    if (CurPtr == MB->getBufferEnd()) {
      // Already at end of the buffer, return just the zero byte at the end.
      return StringRef(CurPtr, 0);
    }
    Token TmpTok;
    RawLexer.getAndAdvanceChar(CurPtr, TmpTok);
    return StringRef(CurPtr, MB->getBufferSize()-(CurPtr-MB->getBufferStart()));
  }

  llvm::StringRef MetaProcessor::SanitizeArg(const std::string& Str) {
    if(Str.empty())
      return Str;

    size_t begins = Str.find_first_not_of(" \t\n");
    size_t ends = Str.find_last_not_of(" \t\n") + 1;

    if (begins == std::string::npos)
      ends = begins + 1;

    return llvm::StringRef(Str.c_str(), ends - begins);
  }

  void MetaProcessor::PrintCommandHelp() {
    llvm::outs() << "Cling meta commands usage\n";
    llvm::outs() << "Syntax: .Command [arg0 arg1 ... argN]\n";
    llvm::outs() << "\n";
    llvm::outs() << ".q\t\t\t\t - Exit the program\n";
    llvm::outs() << ".L <filename>\t\t\t - Load file or library\n";
    llvm::outs() << ".(x|X) <filename>[args]\t\t - Same as .L and runs a ";
    llvm::outs() << "function with signature ret_type filename(args)\n";
    llvm::outs() << ".I [path]\t\t\t - Shows the include path. If a path is ";
    llvm::outs() << "given - adds the path to the list with the include paths\n";
    llvm::outs() << ".@ \t\t\t\t - Cancels and ignores the multiline input\n";
    llvm::outs() << ".rawInput [0|1]\t\t\t - Toggles the wrapping and printing ";
    llvm::outs() << "the execution results of the input\n";
    llvm::outs() << ".dynamicExtensions [0|1]\t - Toggles the use of the ";
    llvm::outs() << "dynamic scopes and the late binding\n";
    llvm::outs() << ".printAST [0|1]\t\t\t - Toggles the printing of input's ";
    llvm::outs() << "corresponding AST nodes\n";
    llvm::outs() << ".help\t\t\t\t - Shows this information\n";
  }

  void MetaProcessor::PrintFileStats() {
    const SourceManager& SM = m_Interp.getCI()->getSourceManager();
    SM.getFileManager().PrintStats();

    llvm::outs() << "\n***\n\n";

    for (SourceManager::fileinfo_iterator I = SM.fileinfo_begin(),
           E = SM.fileinfo_end(); I != E; ++I) {
      llvm::outs() << (*I).first->getName();
      llvm::outs() << "\n";
    }

  }

  // Run a file: .x file[(args)]
  bool MetaProcessor::executeFile(const std::string& fileWithArgs,
                                  Value* result) {
    // Look for start of parameters:

    typedef std::pair<llvm::StringRef,llvm::StringRef> StringRefPair;

    StringRefPair pairFileArgs = llvm::StringRef(fileWithArgs).split('(');
    if (pairFileArgs.second.empty()) {
      pairFileArgs.second = ")";
    }
    StringRefPair pairPathFile = pairFileArgs.first.rsplit('/');
    if (pairPathFile.second.empty()) {
       pairPathFile.second = pairPathFile.first;
    }
    StringRefPair pairFuncExt = pairPathFile.second.rsplit('.');

    //fprintf(stderr, "funcname: %s\n", pairFuncExt.first.data());

    Interpreter::CompilationResult interpRes
       = m_Interp.processLine(std::string("#include \"")
                              + pairFileArgs.first.str()
                              + std::string("\""), true /*raw*/);

    if (interpRes != Interpreter::kFailure) {
       std::string expression = pairFuncExt.first.str()
          + "(" + pairFileArgs.second.str();
       interpRes = m_Interp.processLine(expression, false /*not raw*/, result);
    }

    return (interpRes != Interpreter::kFailure);
  }
} // end namespace cling

<|endoftext|>


<commit_before>/**************************************************************************
 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

/* $Id$ */

/* History of cvs commits:
 *
 * $Log$
 * Revision 1.26  2007/06/18 07:02:44  kharlov
 * Change the signature of EvalLocalPosition() to obey the method virtuality from the parent class
 *
 * Revision 1.25  2007/03/06 06:47:28  kharlov
 * DP:Possibility to use actual vertex position added
 */

//_________________________________________________________________________
//  RecPoint implementation for PHOS-CPV
//  An CpvRecPoint is a cluster of digits
//-- Author: Yuri Kharlov
//  (after Dmitri Peressounko (RRC KI & SUBATECH))
//  30 October 2000

// --- ROOT system ---

#include "TMath.h"
#include "TClonesArray.h"

// --- Standard library ---

// --- AliRoot header files ---
#include "AliLog.h"
#include "AliPHOSGeometry.h"
#include "AliPHOSDigit.h"
#include "AliPHOSCpvRecPoint.h"
#include "AliPHOSLoader.h"

ClassImp(AliPHOSCpvRecPoint)

//____________________________________________________________________________
AliPHOSCpvRecPoint::AliPHOSCpvRecPoint() :
  AliPHOSEmcRecPoint(),
  fLengX(-1),
  fLengZ(-1)
{
  // ctor
}

//____________________________________________________________________________
AliPHOSCpvRecPoint::AliPHOSCpvRecPoint(const char * opt) :
  AliPHOSEmcRecPoint(opt),
  fLengX(-1),
  fLengZ(-1)
{
   // ctor
}

//____________________________________________________________________________
AliPHOSCpvRecPoint::~AliPHOSCpvRecPoint()
{
  // dtor
}

//____________________________________________________________________________
Bool_t AliPHOSCpvRecPoint::AreNeighbours(AliPHOSDigit * digit1, AliPHOSDigit * digit2 ) const
{
  // Tells if (true) or not (false) two digits are neighbors)

  Bool_t aren = kFALSE ;

  AliPHOSGeometry * phosgeom =  AliPHOSGeometry::GetInstance() ;

  Int_t relid1[4] ;
  phosgeom->AbsToRelNumbering(digit1->GetId(), relid1) ;

  Int_t relid2[4] ;
  phosgeom->AbsToRelNumbering(digit2->GetId(), relid2) ;

  Int_t rowdiff = TMath::Abs( relid1[2] - relid2[2] ) ;
  Int_t coldiff = TMath::Abs( relid1[3] - relid2[3] ) ;

  if (( coldiff <= 1 )  && ( rowdiff <= 1 ) && (coldiff + rowdiff > 0))
    aren = kTRUE ;

  return aren ;
}

//____________________________________________________________________________
Int_t AliPHOSCpvRecPoint::Compare(const TObject * obj) const
{
  // Compares two RecPoints according to their position in the PHOS modules

  Float_t delta = 1 ; //Width of "Sorting row". If you changibg this
                      //value (what is senseless) change as vell delta in
                      //AliPHOSTrackSegmentMakerv* and other RecPoints...

  Int_t rv ;

  AliPHOSCpvRecPoint * clu  = (AliPHOSCpvRecPoint *) obj ;

  Int_t phosmod1 = GetPHOSMod() ;
  Int_t phosmod2 = clu->GetPHOSMod() ;

  TVector3 locpos1;
  GetLocalPosition(locpos1) ;
  TVector3 locpos2;
  clu->GetLocalPosition(locpos2) ;

  if(phosmod1 == phosmod2 ) {
    Int_t rowdif = (Int_t)TMath::Ceil(locpos1.X()/delta)-(Int_t)TMath::Ceil(locpos2.X()/delta) ;
    if (rowdif> 0)
      rv = 1 ;
    else if(rowdif < 0)
      rv = -1 ;
    else if(locpos1.Z()>locpos2.Z())
      rv = -1 ;
    else
      rv = 1 ;
  }

  else {
    if(phosmod1 < phosmod2 )
      rv = -1 ;
    else
      rv = 1 ;
  }

  return rv ;

}

//______________________________________________________________________________
void AliPHOSCpvRecPoint::ExecuteEvent(Int_t, Int_t, Int_t ) /*const*/
{
//   // Execute action corresponding to one event
//   //  This member function is called when a AliPHOSRecPoint is clicked with the locator
//   //
//   //  If Left button is clicked on AliPHOSRecPoint, the digits are switched on
//   //  and switched off when the mouse button is released.
//   //

//   //   static Int_t pxold, pyold;

//   AliPHOSLoader * gime =  AliPHOSLoader::GetInstance() ;

//   static TGraph *  digitgraph = 0 ;

//   if (!gPad->IsEditable()) return;

//   TH2F * histo = 0 ;
//   TCanvas * histocanvas ;

//   switch (event) {

//   case kButton1Down: {
//     AliPHOSDigit * digit ;
//     AliPHOSGeometry * phosgeom =  (AliPHOSGeometry *) fGeom ;
//     Int_t iDigit;
//     Int_t relid[4] ;

//     const Int_t kMulDigit = AliPHOSCpvRecPoint::GetDigitsMultiplicity() ;
//     Float_t * xi = new Float_t[kMulDigit] ;
//     Float_t * zi = new Float_t[kMulDigit] ;

//     // create the histogram for the single cluster
//     // 1. gets histogram boundaries
//     Float_t ximax = -999. ;
//     Float_t zimax = -999. ;
//     Float_t ximin = 999. ;
//     Float_t zimin = 999. ;

//     for(iDigit=0; iDigit<kMulDigit; iDigit++) {
//       digit = (AliPHOSDigit *) ( gime->Digit(fDigitsList[iDigit]) ) ;
//       phosgeom->AbsToRelNumbering(digit->GetId(), relid) ;
//       phosgeom->RelPosInModule(relid, xi[iDigit], zi[iDigit]);
//       if ( xi[iDigit] > ximax )
// 	ximax = xi[iDigit] ;
//       if ( xi[iDigit] < ximin )
// 	ximin = xi[iDigit] ;
//       if ( zi[iDigit] > zimax )
// 	zimax = zi[iDigit] ;
//       if ( zi[iDigit] < zimin )
// 	zimin = zi[iDigit] ;
//     }
//     ximax += phosgeom->GetCrystalSize(0) / 2. ;
//     zimax += phosgeom->GetCrystalSize(2) / 2. ;
//     ximin -= phosgeom->GetCrystalSize(0) / 2. ;
//     zimin -= phosgeom->GetCrystalSize(2) / 2. ;
//     Int_t xdim = (int)( (ximax - ximin ) / phosgeom->GetCrystalSize(0) + 0.5  ) ;
//     Int_t zdim = (int)( (zimax - zimin ) / phosgeom->GetCrystalSize(2) + 0.5 ) ;

//     // 2. gets the histogram title

//     Text_t title[100] ;
//     sprintf(title,"Energy=%1.2f GeV ; Digits ; %d ", GetEnergy(), GetDigitsMultiplicity()) ;

//     if (!histo) {
//       delete histo ;
//       histo = 0 ;
//     }
//     histo = new TH2F("cluster3D", title,  xdim, ximin, ximax, zdim, zimin, zimax)  ;

//     Float_t x, z ;
//     for(iDigit=0; iDigit<kMulDigit; iDigit++) {
//       digit = (AliPHOSDigit *) ( gime->Digit(fDigitsList[iDigit]) ) ;
//       phosgeom->AbsToRelNumbering(digit->GetId(), relid) ;
//       phosgeom->RelPosInModule(relid, x, z);
//       histo->Fill(x, z, fEnergyList[iDigit] ) ;
//     }

//     if (!digitgraph) {
//       digitgraph = new TGraph(kMulDigit,xi,zi);
//       digitgraph-> SetMarkerStyle(5) ;
//       digitgraph-> SetMarkerSize(1.) ;
//       digitgraph-> SetMarkerColor(1) ;
//       digitgraph-> Paint("P") ;
//     }

//     Print() ;
//     histocanvas = new TCanvas("cluser", "a single cluster", 600, 500) ;
//     histocanvas->Draw() ;
//     histo->Draw("lego1") ;

//     delete[] xi ;
//     delete[] zi ;

//     break;
//   }

//   case kButton1Up:
//     if (digitgraph) {
//       delete digitgraph  ;
//       digitgraph = 0 ;
//     }
//     break;

//    }
}

//____________________________________________________________________________
void AliPHOSCpvRecPoint::EvalAll(TClonesArray * digits)
{
  // Evaluate local coordinate assuming the vertex in (000) and no inclination
  AliPHOSEmcRecPoint::EvalAll(digits) ;
}
//____________________________________________________________________________
void AliPHOSCpvRecPoint::EvalAll(Float_t logWeight, TVector3 &vtx, TClonesArray * digits)
{
  // wraps other methods
  TVector3 vInc(0,1,0);
  AliPHOSEmcRecPoint::EvalAll(logWeight,vtx,digits) ;
  EvalLocalPosition(logWeight, vtx, digits,vInc) ;
  EvalClusterLengths(digits) ;
}
//____________________________________________________________________________
void AliPHOSCpvRecPoint::EvalLocalPosition(Float_t logWeight, TVector3 & /*vtx */, TClonesArray * digits, TVector3 &/* vInc */)
{
  // Calculates the center of gravity in the local PHOS-module coordinates

  Float_t wtot = 0. ;

  Int_t relid[4] ;

  Float_t x = 0. ;
  Float_t z = 0. ;

  AliPHOSDigit * digit ;

  AliPHOSGeometry * phosgeom =  AliPHOSGeometry::GetInstance();

  Int_t iDigit;

  for(iDigit=0; iDigit<fMulDigit; iDigit++) {
    digit = (AliPHOSDigit *) digits->At(fDigitsList[iDigit]);

    Float_t xi ;
    Float_t zi ;
    phosgeom->AbsToRelNumbering(digit->GetId(), relid) ;
    phosgeom->RelPosInModule(relid, xi, zi);
    if (fAmp>0 && fEnergyList[iDigit]>0) {
      Float_t w = TMath::Max( 0., logWeight + TMath::Log( fEnergyList[iDigit] / fAmp ) ) ;
      x    += xi * w ;
      z    += zi * w ;
      wtot += w ;
    }
//    else
//      AliError(Form("Wrong energy %f and/or amplitude %f\n", fEnergyList[iDigit], fAmp));
  }

  if (wtot != 0) {
    x /= wtot ;
    z /= wtot ;
  } else {
    x = 999 ;
    z = 999 ;
//    if (fMulDigit != 0)
//      AliWarning(Form("Too low log weight factor to evaluate cluster's center" )) ;
  }
  fLocPos.SetX(x)  ;
  fLocPos.SetY(0.) ;
  fLocPos.SetZ(z)  ;

}

//____________________________________________________________________________
void AliPHOSCpvRecPoint::EvalClusterLengths(TClonesArray * digits)
{
  //Modified 15.03.2001 by Dmitri Peressounko

  // Calculates the cluster lengths along X and Z axes
  // These characteristics are needed for CPV to tune
  // digitization+reconstruction to experimental data
  // Yuri Kharlov. 24 October 2000

  Int_t relid[4] ;

  AliPHOSDigit * digit ;

  AliPHOSGeometry * phosgeom =  AliPHOSGeometry::GetInstance();

  const Int_t kMaxLeng=20;
  Int_t idX[kMaxLeng], idZ[kMaxLeng];
  fLengX = 0;
  fLengZ = 0;
  Bool_t dejavu;

  for(Int_t iDigit=0; iDigit<fMulDigit; iDigit++) {
    digit = (AliPHOSDigit *) digits->At(fDigitsList[iDigit]) ;
    Int_t absId = digit->GetId();
    phosgeom->AbsToRelNumbering(absId, relid) ;

    Int_t i;
    dejavu=kFALSE;
    for (i=0; i<fLengX; i++) if (relid[2]==idX[i]) { dejavu=kTRUE; break; }
    if (!dejavu) {
      idX[fLengX]=relid[2];
      fLengX++;
      fLengX = TMath::Min(fLengX,kMaxLeng);
    }

    dejavu=kFALSE;
    for (i=0; i<fLengZ; i++) if (relid[3]==idZ[i]) { dejavu=kTRUE; break; }
    if (!dejavu) {
      idZ[fLengZ]=relid[3];
      fLengZ++;
      fLengZ = TMath::Min(fLengZ,kMaxLeng);
    }
  }
}

//____________________________________________________________________________
void AliPHOSCpvRecPoint::Print(const Option_t *) const
{
  // Print the list of digits belonging to the cluster

  TString message ;
  message  =  "AliPHOSCpvRecPoint: " ;
  message +=  "Digits #   " ;
  AliInfo(message.Data()) ;

  Int_t iDigit;

  for(iDigit=0; iDigit<fMulDigit; iDigit++)
    printf(" %d \n", fDigitsList[iDigit]) ;

  printf("Energies: \n")  ;
  for(iDigit=0; iDigit<fMulDigit; iDigit++)
    printf(" %f ", fEnergyList[iDigit]) ;

  message  = "       Multiplicity    = %d\n" ;
  message += "       Cluster Energy  = %f\n" ;
  message += "       Stored at position %d\n" ;

  printf(message.Data(), fMulDigit, fAmp, GetIndexInList() ) ;

}
<commit_msg>Improve printout<commit_after>/**************************************************************************
 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

/* $Id$ */

/* History of cvs commits:
 *
 * $Log$
 * Revision 1.26  2007/06/18 07:02:44  kharlov
 * Change the signature of EvalLocalPosition() to obey the method virtuality from the parent class
 *
 * Revision 1.25  2007/03/06 06:47:28  kharlov
 * DP:Possibility to use actual vertex position added
 */

//_________________________________________________________________________
//  RecPoint implementation for PHOS-CPV
//  An CpvRecPoint is a cluster of digits
//-- Author: Yuri Kharlov
//  (after Dmitri Peressounko (RRC KI & SUBATECH))
//  30 October 2000

// --- ROOT system ---

#include "TMath.h"
#include "TClonesArray.h"

// --- Standard library ---

// --- AliRoot header files ---
#include "AliLog.h"
#include "AliPHOSGeometry.h"
#include "AliPHOSDigit.h"
#include "AliPHOSCpvRecPoint.h"
#include "AliPHOSLoader.h"

ClassImp(AliPHOSCpvRecPoint)

//____________________________________________________________________________
AliPHOSCpvRecPoint::AliPHOSCpvRecPoint() :
  AliPHOSEmcRecPoint(),
  fLengX(-1),
  fLengZ(-1)
{
  // ctor
}

//____________________________________________________________________________
AliPHOSCpvRecPoint::AliPHOSCpvRecPoint(const char * opt) :
  AliPHOSEmcRecPoint(opt),
  fLengX(-1),
  fLengZ(-1)
{
   // ctor
}

//____________________________________________________________________________
AliPHOSCpvRecPoint::~AliPHOSCpvRecPoint()
{
  // dtor
}

//____________________________________________________________________________
Bool_t AliPHOSCpvRecPoint::AreNeighbours(AliPHOSDigit * digit1, AliPHOSDigit * digit2 ) const
{
  // Tells if (true) or not (false) two digits are neighbors)

  Bool_t aren = kFALSE ;

  AliPHOSGeometry * phosgeom =  AliPHOSGeometry::GetInstance() ;

  Int_t relid1[4] ;
  phosgeom->AbsToRelNumbering(digit1->GetId(), relid1) ;

  Int_t relid2[4] ;
  phosgeom->AbsToRelNumbering(digit2->GetId(), relid2) ;

  Int_t rowdiff = TMath::Abs( relid1[2] - relid2[2] ) ;
  Int_t coldiff = TMath::Abs( relid1[3] - relid2[3] ) ;

  if (( coldiff <= 1 )  && ( rowdiff <= 1 ) && (coldiff + rowdiff > 0))
    aren = kTRUE ;

  return aren ;
}

//____________________________________________________________________________
Int_t AliPHOSCpvRecPoint::Compare(const TObject * obj) const
{
  // Compares two RecPoints according to their position in the PHOS modules

  Float_t delta = 1 ; //Width of "Sorting row". If you changibg this
                      //value (what is senseless) change as vell delta in
                      //AliPHOSTrackSegmentMakerv* and other RecPoints...

  Int_t rv ;

  AliPHOSCpvRecPoint * clu  = (AliPHOSCpvRecPoint *) obj ;

  Int_t phosmod1 = GetPHOSMod() ;
  Int_t phosmod2 = clu->GetPHOSMod() ;

  TVector3 locpos1;
  GetLocalPosition(locpos1) ;
  TVector3 locpos2;
  clu->GetLocalPosition(locpos2) ;

  if(phosmod1 == phosmod2 ) {
    Int_t rowdif = (Int_t)TMath::Ceil(locpos1.X()/delta)-(Int_t)TMath::Ceil(locpos2.X()/delta) ;
    if (rowdif> 0)
      rv = 1 ;
    else if(rowdif < 0)
      rv = -1 ;
    else if(locpos1.Z()>locpos2.Z())
      rv = -1 ;
    else
      rv = 1 ;
  }

  else {
    if(phosmod1 < phosmod2 )
      rv = -1 ;
    else
      rv = 1 ;
  }

  return rv ;

}

//______________________________________________________________________________
void AliPHOSCpvRecPoint::ExecuteEvent(Int_t, Int_t, Int_t ) /*const*/
{
//   // Execute action corresponding to one event
//   //  This member function is called when a AliPHOSRecPoint is clicked with the locator
//   //
//   //  If Left button is clicked on AliPHOSRecPoint, the digits are switched on
//   //  and switched off when the mouse button is released.
//   //

//   //   static Int_t pxold, pyold;

//   AliPHOSLoader * gime =  AliPHOSLoader::GetInstance() ;

//   static TGraph *  digitgraph = 0 ;

//   if (!gPad->IsEditable()) return;

//   TH2F * histo = 0 ;
//   TCanvas * histocanvas ;

//   switch (event) {

//   case kButton1Down: {
//     AliPHOSDigit * digit ;
//     AliPHOSGeometry * phosgeom =  (AliPHOSGeometry *) fGeom ;
//     Int_t iDigit;
//     Int_t relid[4] ;

//     const Int_t kMulDigit = AliPHOSCpvRecPoint::GetDigitsMultiplicity() ;
//     Float_t * xi = new Float_t[kMulDigit] ;
//     Float_t * zi = new Float_t[kMulDigit] ;

//     // create the histogram for the single cluster
//     // 1. gets histogram boundaries
//     Float_t ximax = -999. ;
//     Float_t zimax = -999. ;
//     Float_t ximin = 999. ;
//     Float_t zimin = 999. ;

//     for(iDigit=0; iDigit<kMulDigit; iDigit++) {
//       digit = (AliPHOSDigit *) ( gime->Digit(fDigitsList[iDigit]) ) ;
//       phosgeom->AbsToRelNumbering(digit->GetId(), relid) ;
//       phosgeom->RelPosInModule(relid, xi[iDigit], zi[iDigit]);
//       if ( xi[iDigit] > ximax )
// 	ximax = xi[iDigit] ;
//       if ( xi[iDigit] < ximin )
// 	ximin = xi[iDigit] ;
//       if ( zi[iDigit] > zimax )
// 	zimax = zi[iDigit] ;
//       if ( zi[iDigit] < zimin )
// 	zimin = zi[iDigit] ;
//     }
//     ximax += phosgeom->GetCrystalSize(0) / 2. ;
//     zimax += phosgeom->GetCrystalSize(2) / 2. ;
//     ximin -= phosgeom->GetCrystalSize(0) / 2. ;
//     zimin -= phosgeom->GetCrystalSize(2) / 2. ;
//     Int_t xdim = (int)( (ximax - ximin ) / phosgeom->GetCrystalSize(0) + 0.5  ) ;
//     Int_t zdim = (int)( (zimax - zimin ) / phosgeom->GetCrystalSize(2) + 0.5 ) ;

//     // 2. gets the histogram title

//     Text_t title[100] ;
//     sprintf(title,"Energy=%1.2f GeV ; Digits ; %d ", GetEnergy(), GetDigitsMultiplicity()) ;

//     if (!histo) {
//       delete histo ;
//       histo = 0 ;
//     }
//     histo = new TH2F("cluster3D", title,  xdim, ximin, ximax, zdim, zimin, zimax)  ;

//     Float_t x, z ;
//     for(iDigit=0; iDigit<kMulDigit; iDigit++) {
//       digit = (AliPHOSDigit *) ( gime->Digit(fDigitsList[iDigit]) ) ;
//       phosgeom->AbsToRelNumbering(digit->GetId(), relid) ;
//       phosgeom->RelPosInModule(relid, x, z);
//       histo->Fill(x, z, fEnergyList[iDigit] ) ;
//     }

//     if (!digitgraph) {
//       digitgraph = new TGraph(kMulDigit,xi,zi);
//       digitgraph-> SetMarkerStyle(5) ;
//       digitgraph-> SetMarkerSize(1.) ;
//       digitgraph-> SetMarkerColor(1) ;
//       digitgraph-> Paint("P") ;
//     }

//     Print() ;
//     histocanvas = new TCanvas("cluser", "a single cluster", 600, 500) ;
//     histocanvas->Draw() ;
//     histo->Draw("lego1") ;

//     delete[] xi ;
//     delete[] zi ;

//     break;
//   }

//   case kButton1Up:
//     if (digitgraph) {
//       delete digitgraph  ;
//       digitgraph = 0 ;
//     }
//     break;

//    }
}

//____________________________________________________________________________
void AliPHOSCpvRecPoint::EvalAll(TClonesArray * digits)
{
  // Evaluate local coordinate assuming the vertex in (000) and no inclination
  AliPHOSEmcRecPoint::EvalAll(digits) ;
}
//____________________________________________________________________________
void AliPHOSCpvRecPoint::EvalAll(Float_t logWeight, TVector3 &vtx, TClonesArray * digits)
{
  // wraps other methods
  TVector3 vInc(0,1,0);
  AliPHOSEmcRecPoint::EvalAll(logWeight,vtx,digits) ;
  EvalLocalPosition(logWeight, vtx, digits,vInc) ;
  EvalClusterLengths(digits) ;
}
//____________________________________________________________________________
void AliPHOSCpvRecPoint::EvalLocalPosition(Float_t logWeight, TVector3 & /*vtx */, TClonesArray * digits, TVector3 &/* vInc */)
{
  // Calculates the center of gravity in the local PHOS-module coordinates

  Float_t wtot = 0. ;

  Int_t relid[4] ;

  Float_t x = 0. ;
  Float_t z = 0. ;

  AliPHOSDigit * digit ;

  AliPHOSGeometry * phosgeom =  AliPHOSGeometry::GetInstance();

  Int_t iDigit;

  for(iDigit=0; iDigit<fMulDigit; iDigit++) {
    digit = (AliPHOSDigit *) digits->At(fDigitsList[iDigit]);

    Float_t xi ;
    Float_t zi ;
    phosgeom->AbsToRelNumbering(digit->GetId(), relid) ;
    phosgeom->RelPosInModule(relid, xi, zi);
    if (fAmp>0 && fEnergyList[iDigit]>0) {
      Float_t w = TMath::Max( 0., logWeight + TMath::Log( fEnergyList[iDigit] / fAmp ) ) ;
      x    += xi * w ;
      z    += zi * w ;
      wtot += w ;
    }
//    else
//      AliError(Form("Wrong energy %f and/or amplitude %f\n", fEnergyList[iDigit], fAmp));
  }

  if (wtot != 0) {
    x /= wtot ;
    z /= wtot ;
  } else {
    x = 999 ;
    z = 999 ;
//    if (fMulDigit != 0)
//      AliWarning(Form("Too low log weight factor to evaluate cluster's center" )) ;
  }
  fLocPos.SetX(x)  ;
  fLocPos.SetY(0.) ;
  fLocPos.SetZ(z)  ;

}

//____________________________________________________________________________
void AliPHOSCpvRecPoint::EvalClusterLengths(TClonesArray * digits)
{
  //Modified 15.03.2001 by Dmitri Peressounko

  // Calculates the cluster lengths along X and Z axes
  // These characteristics are needed for CPV to tune
  // digitization+reconstruction to experimental data
  // Yuri Kharlov. 24 October 2000

  Int_t relid[4] ;

  AliPHOSDigit * digit ;

  AliPHOSGeometry * phosgeom =  AliPHOSGeometry::GetInstance();

  const Int_t kMaxLeng=20;
  Int_t idX[kMaxLeng], idZ[kMaxLeng];
  fLengX = 0;
  fLengZ = 0;
  Bool_t dejavu;

  for(Int_t iDigit=0; iDigit<fMulDigit; iDigit++) {
    digit = (AliPHOSDigit *) digits->At(fDigitsList[iDigit]) ;
    Int_t absId = digit->GetId();
    phosgeom->AbsToRelNumbering(absId, relid) ;

    Int_t i;
    dejavu=kFALSE;
    for (i=0; i<fLengX; i++) if (relid[2]==idX[i]) { dejavu=kTRUE; break; }
    if (!dejavu) {
      idX[fLengX]=relid[2];
      fLengX++;
      fLengX = TMath::Min(fLengX,kMaxLeng);
    }

    dejavu=kFALSE;
    for (i=0; i<fLengZ; i++) if (relid[3]==idZ[i]) { dejavu=kTRUE; break; }
    if (!dejavu) {
      idZ[fLengZ]=relid[3];
      fLengZ++;
      fLengZ = TMath::Min(fLengZ,kMaxLeng);
    }
  }
}

//____________________________________________________________________________
void AliPHOSCpvRecPoint::Print(const Option_t *) const
{
  // Print the list of digits belonging to the cluster

  TString message ;
  message  =  "AliPHOSCpvRecPoint: " ;
  AliInfo(message.Data()) ;

  Int_t iDigit;

  for(iDigit=0; iDigit<fMulDigit; iDigit++)
    printf("\tDigit %d: id=%d, A=%f\n", iDigit, fDigitsList[iDigit], fEnergyList[iDigit]) ;

  message  = "\tPad multiplicity    = %d\n" ;
  message += "\tCluster amplitude  = %f\n" ;
  message += "\tStored at position %d\n" ;

  printf(message.Data(), fMulDigit, fAmp, GetIndexInList() ) ;

}
<|endoftext|>


<commit_before>#include <vector>
#include <cstdint>
#include <iostream>
#include <fstream>
#include <iomanip>
#include <algorithm>
#include <random>
#include <cmath>

#include "catch.hpp"
#include "detail/heapqueue.hpp"
#include "fixtures.hpp"

TEST_CASE_METHOD( image_fixture, "fixture data correct", "[image]" ) {

    REQUIRE( data_.data() != nullptr );
    REQUIRE( data_[0] < 1.f );

    SECTION("small rectangle (x,y) = [6:11,2:5] was set"){
        REQUIRE( data_[13*shape[1]+2] != 0.f );
        REQUIRE( data_[13*shape[1]+2] == 42.f );
    }

    SECTION("small circle at (24,24) with radius 4"){
        REQUIRE( data_[2*shape[1]+12] != 0.f );
        REQUIRE( data_[2*shape[1]+12] == 100.f );
    }
}

TEST_CASE( "create heap from vector", "[any]" ) {

    const std::vector<float> nums = {5.f,  1.f, 7.f, 3.f};

    SECTION("make_heap gives same root as python example"){

        auto data = nums;
        std::make_heap(std::begin(data),std::end(data));
        REQUIRE( data.front() == Approx( 7.f ));

    }

    const std::vector<int>   foo  = {50, 70, 10, 30};

    SECTION("make_heap gives same root as python example with tuple"){

        std::vector<std::tuple<float,int> >   data(nums.size());
        std::transform(std::begin(nums),std::end(nums),
                       std::begin(foo),
                       std::begin(data),
                       [](const float& _lhs, const int& _rhs){
                           return std::make_tuple(_lhs,_rhs);
                       }
            );

        std::make_heap(std::begin(data),std::end(data));

        REQUIRE( std::get<0>(data.front()) == Approx( 7.f ));

    }

    SECTION("make_heap gives same root as python example with tuple and custom comparator"){

        std::vector<std::tuple<float,int> >   data(nums.size());
        std::transform(std::begin(nums),std::end(nums),
                       std::begin(foo),
                       std::begin(data),
                       [](const float& _lhs, const int& _rhs){
                           return std::make_tuple(_lhs,_rhs);
                       }
            );

        auto comp = [](const std::tuple<float,int>& _lhs, const std::tuple<float,int>& _rhs){
            return std::get<0>(_lhs) < std::get<0>(_rhs);
        };
        std::make_heap(std::begin(data),std::end(data),comp);

        REQUIRE( std::get<0>(data.front()) == Approx( 7.f ));

    }

}

TEST_CASE_METHOD( image_fixture, "create heap from image", "[image]" ) {

    REQUIRE( data_.data() != nullptr );

    SECTION("default heap is not empty from input data"){

        auto q = ndtess::heap::build(data_.data(),shape);
        REQUIRE( ! q.empty() );

    }

    SECTION("compare outcome to python implementation with default map"){

        auto q = ndtess::heap::build(data_.data(),shape);

        REQUIRE( q.size() == 239 );

        auto i = q.top();

        REQUIRE( std::get<0>(i) == Approx ( 1.f ) );
        CHECK( std::get<1>(i) == 10 );
        CHECK( std::get<2>(i) == 0 );
        REQUIRE( std::get<3>(i) == Approx ( 100.f ) );

    }

    SECTION("compare outcome to python implementation with constant map"){

        auto q = ndtess::heap::build(data_.data(),shape, constant_map_.data());

        REQUIRE( q.size() == 239 );

        auto i = q.top();

        REQUIRE( std::get<1>(i) == 10 );
        REQUIRE( std::get<2>(i) == 0 );
        REQUIRE( std::get<3>(i) == Approx ( 100.f ) );

    }

    SECTION("compare outcome to python implementation with sinus map"){

        auto q = ndtess::heap::build(data_.data(),shape, constant_map_.data());

        REQUIRE( q.size() == 239 );

        auto i = q.top();

        REQUIRE( std::get<1>(i) == 10 );
        REQUIRE( std::get<2>(i) == 0 );
        REQUIRE( std::get<3>(i) == Approx ( 100.f ) );

    }

    SECTION("compare outcome to python implementation with random map"){

        auto q = ndtess::heap::build(data_.data(),shape, random_map_.data());

        REQUIRE( q.size() == 239 );

        auto i = q.top();

        // REQUIRE( std::get<1>(i) == 15 );
        // REQUIRE( std::get<2>(i) == 7 );
        REQUIRE( std::get<3>(i) == Approx ( 100.f ) );

    }
}
<commit_msg>added tuple for expected outcome<commit_after>#include <vector>
#include <cstdint>
#include <iostream>
#include <fstream>
#include <iomanip>
#include <algorithm>
#include <random>
#include <cmath>

#include "catch.hpp"
#include "detail/heapqueue.hpp"
#include "fixtures.hpp"

TEST_CASE_METHOD( image_fixture, "fixture data correct", "[image]" ) {

    REQUIRE( data_.data() != nullptr );
    REQUIRE( data_[0] < 1.f );

    SECTION("small rectangle (x,y) = [6:11,2:5] was set"){
        REQUIRE( data_[13*shape[1]+2] != 0.f );
        REQUIRE( data_[13*shape[1]+2] == 42.f );
    }

    SECTION("small circle at (24,24) with radius 4"){
        REQUIRE( data_[2*shape[1]+12] != 0.f );
        REQUIRE( data_[2*shape[1]+12] == 100.f );
    }
}

TEST_CASE( "create heap from vector", "[any]" ) {

    const std::vector<float> nums = {5.f,  1.f, 7.f, 3.f};

    SECTION("make_heap gives same root as python example"){

        auto data = nums;
        std::make_heap(std::begin(data),std::end(data));
        REQUIRE( data.front() == Approx( 7.f ));

    }

    const std::vector<int>   foo  = {50, 70, 10, 30};

    SECTION("make_heap gives same root as python example with tuple"){

        std::vector<std::tuple<float,int> >   data(nums.size());
        std::transform(std::begin(nums),std::end(nums),
                       std::begin(foo),
                       std::begin(data),
                       [](const float& _lhs, const int& _rhs){
                           return std::make_tuple(_lhs,_rhs);
                       }
            );

        std::make_heap(std::begin(data),std::end(data));

        REQUIRE( std::get<0>(data.front()) == Approx( 7.f ));

    }

    SECTION("make_heap gives same root as python example with tuple and custom comparator"){

        std::vector<std::tuple<float,int> >   data(nums.size());
        std::transform(std::begin(nums),std::end(nums),
                       std::begin(foo),
                       std::begin(data),
                       [](const float& _lhs, const int& _rhs){
                           return std::make_tuple(_lhs,_rhs);
                       }
            );

        auto comp = [](const std::tuple<float,int>& _lhs, const std::tuple<float,int>& _rhs){
            return std::get<0>(_lhs) < std::get<0>(_rhs);
        };
        std::make_heap(std::begin(data),std::end(data),comp);

        REQUIRE( std::get<0>(data.front()) == Approx( 7.f ));

    }

}

TEST_CASE_METHOD( image_fixture, "create heap from image", "[image]" ) {

    REQUIRE( data_.data() != nullptr );

    SECTION("default heap is not empty from input data"){

        auto q = ndtess::heap::build(data_.data(),shape);
        REQUIRE( ! q.empty() );

    }

    SECTION("compare outcome to python implementation with default map (zeroes)"){

        auto q = ndtess::heap::build(data_.data(),shape);

        REQUIRE( q.size() == 239 );

        //auto i = q.top();

        // REQUIRE( std::get<0>(i) == Approx ( 1.f ) );
        // CHECK( std::get<1>(i) == 10 );
        // CHECK( std::get<2>(i) == 0 );
        // REQUIRE( std::get<3>(i) == Approx ( 100.f ) );

        const std::vector<ndtess::item<float> > expected = {std::make_tuple(1.f, 10, 0, 100.f),
                                                    std::make_tuple(1.f, 11, 0, 100.f),
                                                    std::make_tuple(1.f, 12, 0, 100.f),
                                                    std::make_tuple(1.f, 13, 0, 100.f),
                                                    std::make_tuple(1.f, 14, 0, 100.f),
                                                    std::make_tuple(1.f,  9, 1, 100.f),
                                                    std::make_tuple(1.f,  9, 1, 100.f),
                                                    std::make_tuple(1.f, 10, 1, 100.f),
                                                    std::make_tuple(1.f, 10, 1, 100.f),
                                                    std::make_tuple(1.f, 11, 1, 100.f),
                                                    std::make_tuple(1.f, 11, 1, 100.f),
                                                    std::make_tuple(1.f, 11, 1, 100.f),
                                                    std::make_tuple(1.f, 12, 1, 100.f),
                                                    std::make_tuple(1.f, 12, 1, 100.f),
                                                    std::make_tuple(1.f, 12, 1, 100.f),
                                                    std::make_tuple(1.f, 13, 1, 100.f)
        };

        for( int i = 0;i < expected.size() ;++i){
            auto t = q.top();
            auto e = expected[i];
            INFO("item :: " << i);
            REQUIRE( std::get<0>(t) == Approx ( std::get<0>(e) ) );
            CHECK  ( std::get<1>(t) == std::get<1>(e) );
            CHECK  ( std::get<2>(t) == std::get<2>(e)  );
            REQUIRE( std::get<3>(t) == Approx (  std::get<3>(e) ) );
            q.pop();
        }
    }

    SECTION("compare outcome to python implementation with constant map"){

        auto q = ndtess::heap::build(data_.data(),shape, constant_map_.data());

        REQUIRE( q.size() == 239 );

        auto i = q.top();

        REQUIRE( std::get<1>(i) == 10 );
        REQUIRE( std::get<2>(i) == 0 );
        REQUIRE( std::get<3>(i) == Approx ( 100.f ) );

    }

    SECTION("compare outcome to python implementation with sinus map"){

        auto q = ndtess::heap::build(data_.data(),shape, constant_map_.data());

        REQUIRE( q.size() == 239 );

        auto i = q.top();

        REQUIRE( std::get<1>(i) == 10 );
        REQUIRE( std::get<2>(i) == 0 );
        REQUIRE( std::get<3>(i) == Approx ( 100.f ) );

    }

    SECTION("compare outcome to python implementation with random map"){

        auto q = ndtess::heap::build(data_.data(),shape, random_map_.data());

        REQUIRE( q.size() == 239 );

        auto i = q.top();

        // REQUIRE( std::get<1>(i) == 15 );
        // REQUIRE( std::get<2>(i) == 7 );
        REQUIRE( std::get<3>(i) == Approx ( 100.f ) );

    }
}
<|endoftext|>


<commit_before>/***************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (testabilitydriver@nokia.com)
**
** This file is part of Testability Driver.
**
** If you have questions regarding the use of this file, please contact
** Nokia at testabilitydriver@nokia.com .
**
** 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
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/

#include <QtSql>
#include "tdriver_translationdb.h"
#include <tdriver_debug_macros.h>

TDriverTranslationDb::TDriverTranslationDb()
{
    dbType = Undefined;
    connected = false;
    languageFilter << "English-GB";
}

TDriverTranslationDb::~TDriverTranslationDb()
{
    if (connected) disconnectDB();
}

bool TDriverTranslationDb::connectDB(QString aHost, QString aName, QString aTable, QString aUser, QString aPassword)
{
    QSqlDatabase db;
    dbType = MySQL;

    db = QSqlDatabase::addDatabase("QMYSQL");
    db.setHostName(aHost);
    db.setDatabaseName(aName);
    db.setUserName(aUser);
    db.setPassword(aPassword);
    locTable = aTable;
    connected =  db.open();
    if (!connected) {
        qDebug() << FFL << "connection error:" << db.lastError().text();
    }
    return connected;
}

void TDriverTranslationDb::disconnectDB()
{
    dbType = Undefined;
    QSqlDatabase db =  QSqlDatabase::database();
    db.close();
    connected = false;
}

EDbType TDriverTranslationDb::getDbType()
{
    return dbType;
}

QStringList TDriverTranslationDb::getAvailableLanguages()
{
    availableLanguages.clear();
    if (connected)
    {
        QSqlQuery query;
        query.exec("select COLUMN_NAME from `information_schema`.`COLUMNS` where TABLE_NAME = '" + locTable + "'");
        while (query.next())
        {
            QString col_name = query.value(0).toString();
            // Ignore ID, FNAME and LNAME columns
            if (col_name.toUpper() != "ID" && col_name.toUpper() != "FNAME" && col_name.toUpper() != "LNAME" )
                availableLanguages << col_name ;
        }
    }
    return availableLanguages;
}

void TDriverTranslationDb::setLanguageFilter(QStringList filter)
{
    languageFilter = filter;
}

QStringList TDriverTranslationDb::getLanguageFilter()
{
    return languageFilter;
}

QList<QStringList> TDriverTranslationDb::getTranslationsLike(QString searchText)
{
    QList<QStringList> results;
    if (connected)
    {
        QSqlQuery query;

        // If languageFilter not set
        if (languageFilter.isEmpty())
        {
//            // This query requires a FULLTEXT index to be set on all language columns on the DB
//            QString language_cols = "`" + availableLanguages.join("`, `") + "`";
//            query.exec("select " + language_cols + " from " + locTable + " where match (" + language_cols + ") against ('" + searchText + "')");
//            while (query.next())
//            {
//                // If using match against columns query,
//                // select from each result the column with the match
//                int index = 0;
//                while (query.value(index).isValid())
//                {
//                    if (query.value(index).toString().contains( searchText, Qt::CaseInsensitive))
//                    {
//                        results << query.value(index).toString();
//                        break;
//                    }
//                    index++;
//                }
//            }
        }

        // If languageFilter set
        else
        {
            //One query per language
            foreach (QString language, languageFilter)
            {
                query.exec("select lname, `" + language + "` from " + locTable + " where `" + language + "` like '%" + searchText + "%'");
                while (query.next())
                {
                    results << (QStringList() << query.value(0).toString()  << query.value(1).toString() << language );
                }
            }
        }
    }
    return results;
}

// Several LNames can have the same translation
// 1-Translation -> Many-Lnames (in the same language)
QStringList TDriverTranslationDb::findLNames(QString translation, QString language)
{
    QStringList results;
    if (connected)
    {
        QSqlQuery query;
        query.exec("select LNAME from " + locTable + " where " + language + " = '" + translation + "'");
        while (query.next())
        {
            results << query.value(0).toString();
        }
    }
    return results;
}

QList<QStringList> TDriverTranslationDb::findLNames(QString translation)
{
    QList<QStringList> results;

    if (languageFilter.isEmpty())
    {
        // TODO if languageFilter not set
    }
    else
    {
        foreach (QString language, languageFilter)
        {
            results << ( QStringList() << findLNames(translation, language) << language );
        }
    }
    return results;
}

// Same LNames (on diferent files (FNames)) can have different translations
// LNames are not unique ( Same LName for different language file (FName) )
// Many-LName -> Many-Translations (in the same language)
QStringList TDriverTranslationDb::findTranslations(QString lname, QString language)
{
    QStringList results;
    if (connected)
    {
        QSqlQuery query;
        query.exec("select " + language + " from " + locTable + " where LNAME = '" + lname + "'");
        while (query.next())
        {
            results << query.value(0).toString();
        }
    }
    return results ;
}

QList<QStringList> TDriverTranslationDb::findTranslations(QString lname)
{
    QList<QStringList> results;

    if (languageFilter.isEmpty())
    {
        // TODO if languageFilter not set
    }
    else
    {
        foreach (QString language, languageFilter)
        {
            results << (QStringList() << findTranslations( lname, language) << language);
        }
    }

    return results;
}

<commit_msg>Updated logical name search to search exact match and if not found then seek strings that contain the searched string<commit_after>/***************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (testabilitydriver@nokia.com)
**
** This file is part of Testability Driver.
**
** If you have questions regarding the use of this file, please contact
** Nokia at testabilitydriver@nokia.com .
**
** 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
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/

#include <QtSql>
#include "tdriver_translationdb.h"
#include <tdriver_debug_macros.h>

TDriverTranslationDb::TDriverTranslationDb()
{
    dbType = Undefined;
    connected = false;
    languageFilter << "English-GB";
}

TDriverTranslationDb::~TDriverTranslationDb()
{
    if (connected) disconnectDB();
}

bool TDriverTranslationDb::connectDB(QString aHost, QString aName, QString aTable, QString aUser, QString aPassword)
{
    QSqlDatabase db;
    dbType = MySQL;

    db = QSqlDatabase::addDatabase("QMYSQL");
    db.setHostName(aHost);
    db.setDatabaseName(aName);
    db.setUserName(aUser);
    db.setPassword(aPassword);
    locTable = aTable;
    connected =  db.open();
    if (!connected) {
        qDebug() << FFL << "connection error:" << db.lastError().text();
    }
    return connected;
}

void TDriverTranslationDb::disconnectDB()
{
    dbType = Undefined;
    QSqlDatabase db =  QSqlDatabase::database();
    db.close();
    connected = false;
}

EDbType TDriverTranslationDb::getDbType()
{
    return dbType;
}

QStringList TDriverTranslationDb::getAvailableLanguages()
{
    availableLanguages.clear();
    if (connected)
    {
        QSqlQuery query;
        query.exec("select COLUMN_NAME from `information_schema`.`COLUMNS` where TABLE_NAME = '" + locTable + "'");
        while (query.next())
        {
            QString col_name = query.value(0).toString();
            // Ignore ID, FNAME and LNAME columns
            if (col_name.toUpper() != "ID" && col_name.toUpper() != "FNAME" && col_name.toUpper() != "LNAME" )
                availableLanguages << col_name ;
        }
    }
    return availableLanguages;
}

void TDriverTranslationDb::setLanguageFilter(QStringList filter)
{
    languageFilter = filter;
}

QStringList TDriverTranslationDb::getLanguageFilter()
{
    return languageFilter;
}

QList<QStringList> TDriverTranslationDb::getTranslationsLike(QString searchText)
{
    QList<QStringList> results;
    if (connected)
    {
        QSqlQuery query;

        // If languageFilter not set
        if (languageFilter.isEmpty())
        {
//            // This query requires a FULLTEXT index to be set on all language columns on the DB
//            QString language_cols = "`" + availableLanguages.join("`, `") + "`";
//            query.exec("select " + language_cols + " from " + locTable + " where match (" + language_cols + ") against ('" + searchText + "')");
//            while (query.next())
//            {
//                // If using match against columns query,
//                // select from each result the column with the match
//                int index = 0;
//                while (query.value(index).isValid())
//                {
//                    if (query.value(index).toString().contains( searchText, Qt::CaseInsensitive))
//                    {
//                        results << query.value(index).toString();
//                        break;
//                    }
//                    index++;
//                }
//            }
        }

        // If languageFilter set
        else
        {
            //One query per language
            foreach (QString language, languageFilter)
            {
                //Try to find exact match
                query.exec("select lname, `" + language + "` from " + locTable + " where `" + language + "` = '" + searchText + "'");

                if (query.size() <= 0){
                  query.exec("select lname, `" + language + "` from " + locTable + " where `" + language + "` like '%" + searchText + "%'");
                }

                while (query.next())
                {
                    results << (QStringList() << query.value(0).toString()  << query.value(1).toString() << language );
                }

            }
        }
    }
    return results;
}

// Several LNames can have the same translation
// 1-Translation -> Many-Lnames (in the same language)
QStringList TDriverTranslationDb::findLNames(QString translation, QString language)
{
    QStringList results;
    if (connected)
    {
        QSqlQuery query;
        query.exec("select LNAME from " + locTable + " where " + language + " = '" + translation + "'");
        while (query.next())
        {
            results << query.value(0).toString();
        }
    }
    return results;
}

QList<QStringList> TDriverTranslationDb::findLNames(QString translation)
{
    QList<QStringList> results;

    if (languageFilter.isEmpty())
    {
        // TODO if languageFilter not set
    }
    else
    {
        foreach (QString language, languageFilter)
        {
            results << ( QStringList() << findLNames(translation, language) << language );
        }
    }
    return results;
}

// Same LNames (on diferent files (FNames)) can have different translations
// LNames are not unique ( Same LName for different language file (FName) )
// Many-LName -> Many-Translations (in the same language)
QStringList TDriverTranslationDb::findTranslations(QString lname, QString language)
{
    QStringList results;
    if (connected)
    {
        QSqlQuery query;
        query.exec("select " + language + " from " + locTable + " where LNAME = '" + lname + "'");
        while (query.next())
        {
            results << query.value(0).toString();
        }
    }
    return results ;
}

QList<QStringList> TDriverTranslationDb::findTranslations(QString lname)
{
    QList<QStringList> results;

    if (languageFilter.isEmpty())
    {
        // TODO if languageFilter not set
    }
    else
    {
        foreach (QString language, languageFilter)
        {
            results << (QStringList() << findTranslations( lname, language) << language);
        }
    }

    return results;
}

<|endoftext|>


<commit_before>#include "PNEvolution.hpp"
#include <cmath>

using Quaternions::Quaternion;
using Quaternions::exp;
using Quaternions::conjugate;

void AngularVelocityIntegrand(const double r0, const double r1, const double r2,
                              const double omega0, const double omega1, const double omega2,
                              double& rdot0, double& rdot1, double& rdot2)
{
  const double rmag = sqrt(r0*r0+r1*r1+r2*r2);

  // If rmag is basically zero, return an answer assuming exactly zero
  if(rmag<Quaternion_Epsilon) {
    rdot0 = omega0/2.0;
    rdot1 = omega1/2.0;
    rdot2 = omega2/2.0;
    return;
  }

  // Otherwise, actually do the calculation
  const double dotTerm = (r0*omega0+r1*omega1+r2*omega2)/(rmag*rmag);
  const double cotTerm = rmag/(2*tan(rmag));
  rdot0 = (omega0 - r0*dotTerm)*cotTerm + r0*dotTerm + 0.5*(omega1*r2 - omega2*r1);
  rdot1 = (omega1 - r1*dotTerm)*cotTerm + r1*dotTerm + 0.5*(omega2*r0 - omega0*r2);
  rdot2 = (omega2 - r2*dotTerm)*cotTerm + r2*dotTerm + 0.5*(omega0*r1 - omega1*r0);
  return;
}

void AngularVelocityIntegrand(const double r0, const double r1,
                              const double omega0, const double omega1, double omega2,
                              double& rdot0, double& rdot1)
{
  const double rmag = sqrt(r0*r0+r1*r1);

  // If rmag is basically zero, return an answer assuming exactly zero
  if(rmag<Quaternion_Epsilon) {
    rdot0 = omega0/2.0;
    rdot1 = omega1/2.0;
    return;
  }

  // Otherwise, actually do the calculation
  const double dotTerm = (r0*omega0+r1*omega1)/(rmag*rmag);
  const double cotTerm = rmag/(2*tan(rmag));
  rdot0 = (omega0 - r0*dotTerm)*cotTerm + r0*dotTerm - 0.5*omega2*r1;
  rdot1 = (omega1 - r1*dotTerm)*cotTerm + r1*dotTerm + 0.5*omega2*r0;
  return;
}

const Quaternions::Quaternion xHat(0,1.0,0,0);
const Quaternions::Quaternion yHat(0,0,1.0,0);
const Quaternions::Quaternion zHat(0,0,0,1.0);

#include "PNApproximants.ipp"
<commit_msg>Moving integrands to Quaternions module<commit_after>#include "PNEvolution.hpp"
#include <cmath>

using Quaternions::Quaternion;
using Quaternions::exp;
using Quaternions::conjugate;
using Quaternions::xHat;
using Quaternions::yHat;
using Quaternions::zHat;

#include "PNApproximants.ipp"

<|endoftext|>


<commit_before>/*
    kopete.cpp

    Kopete Instant Messenger Main Class

    Copyright (c) 2001-2002  by Duncan Mac-Vicar Prett   <duncan@kde.org>
    Copyright (c) 2002-2003  by Martijn Klingens         <klingens@kde.org>

    Kopete    (c) 2001-2003  by the Kopete developers    <kopete-devel@kde.org>

    *************************************************************************
    *                                                                       *
    * This program is free software; you can redistribute it and/or modify  *
    * it under the terms of the GNU General Public License as published by  *
    * the Free Software Foundation; either version 2 of the License, or     *
    * (at your option) any later version.                                   *
    *                                                                       *
    *************************************************************************
*/

#include "kopeteapplication.h"

#include <qtimer.h>
#include <qregexp.h>

#include <kconfig.h>
#include <kdebug.h>
#include <klocale.h>
#include <kcmdlineargs.h>
#include <kmessagebox.h>

#include "kopeteaccount.h"
#include "kopeteaccountmanager.h"
#include "kopetecommandhandler.h"
#include "kopetecontactlist.h"
#include "kopeteglobal.h"
#include "kopetemimesourcefactory.h"
#include "kopetemimetypehandler.h"
#include "kopetepluginmanager.h"
#include "kopeteprotocol.h"
#include "kopetestdaction.h"
#include "kopeteuiglobal.h"
#include "kopetewindow.h"
#include "kopeteprefs.h"
#include "kopeteviewmanager.h"

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

KopeteApplication::KopeteApplication()
: KUniqueApplication( true, true, true )
{
	m_isShuttingDown = false;
	m_mainWindow = new KopeteWindow( 0, "mainWindow" );

	/* KMainWindow is very broken from our point of view - it deref()'s the app
	 * when the last visible KMainWindow is destroyed. This is broken for a number
	 * of reasons, not least because it can happen more than once within a single
	 * instance of Kopete. Also, our main window is hidden when it's in the tray,
	 * and closing the last chatwindow when in that state can cause the app to quit.
	 *
	 * KopeteApplication's reference counting scheme is different to that of a normal
	 * KDE application. It works as follows: the Kopete::PluginManager has a reference
	 * to the application. No windows ever call KMainWindow::closeEvent, so KMainWindow
	 * doesn't stupidly deref() our application. This ensures that the application
	 * reference counting still works properly, and that the application terminates
	 * neither too early (bug 75805) nor too late (bug 71657). - Richard
	 */

	// KApplication sets the reference count to 1 on startup. Kopete::PluginManager has a
	// reference to us once created, so create it and drop our own reference.
	Kopete::PluginManager::self();
	deref();

	Kopete::UI::Global::setMainWidget( m_mainWindow );

	/*
	 * FIXME: This is a workaround for a quite odd problem:
	 * When starting up kopete and the msn plugin gets loaded it can bring up
	 * a messagebox, in case the msg configuration is missing. This messagebox
	 * will result in a QApplication::enter_loop() call, an event loop is
	 * created. At this point however the loop_level is 0, because this is all
	 * still inside the KopeteApplication constructor, before the exec() call from main.
	 * When the messagebox is finished the loop_level will drop down to zero and
	 * QApplication thinks the application shuts down (this is usually the case
	 * when the loop_level goes down to zero) . So it emits aboutToQuit(), to
	 * which KApplication is connected and re-emits shutdown() , to which again
	 * KMainWindow (a KopeteWindow instance exists already) is connected. KMainWindow's
	 * shuttingDown() slot calls queryExit() which results in KopeteWindow::queryExit()
	 * calling unloadPlugins() . This of course is wrong and just shouldn't happen.
	 * The workaround is to simply delay the initialization of all this to a point
	 * where the loop_level is already > 0 . That is why I moved all the code from
	 * the constructor to the initialize() method and added this single-shot-timer
	 * setup. (Simon)
	 *
	 * Additionally, it makes the GUI appear less 'blocking' during startup, so
	 * there is a secondary benefit as well here. (Martijn)
	 */
	QTimer::singleShot( 0, this, SLOT( slotLoadPlugins() ) );

	m_mimeFactory = new Kopete::MimeSourceFactory;
	QMimeSourceFactory::addFactory( m_mimeFactory );

	//Create the emoticon installer
	m_emoticonHandler = new Kopete::EmoticonMimeTypeHandler;
}

KopeteApplication::~KopeteApplication()
{
	kdDebug( 14000 ) << k_funcinfo << endl;

	delete m_mainWindow;
	delete m_emoticonHandler;
	delete m_mimeFactory;
	//kdDebug( 14000 ) << k_funcinfo << "Done" << endl;
}

void KopeteApplication::slotLoadPlugins()
{
	//Create the command handler (looks silly)
	Kopete::CommandHandler::commandHandler();

	//Create the view manager
	KopeteViewManager::viewManager();

	Kopete::AccountManager::self()->load();
	Kopete::ContactList::self()->load();

	KConfig *config = KGlobal::config();

	// Parse command-line arguments
	KCmdLineArgs *args = KCmdLineArgs::parsedArgs();

	bool showConfigDialog = false;

	config->setGroup( "Plugins" );

	/* FIXME: This is crap, if something purged that groups but your accounts
	 * are still working kopete will load the necessary plugins but still show the
	 * stupid accounts dialog (of course empty at that time because account data
	 * gets loaded later on). [mETz - 29.05.2004]
	 */
	if ( !config->hasGroup( "Plugins" ) )
		showConfigDialog = true;

	// Listen to arguments
	/*
	// TODO: conflicts with emoticon installer and the general meaning
	// of %U in kopete.desktop
	if ( args->count() > 0 )
	{
		showConfigDialog = false;
		for ( int i = 0; i < args->count(); i++ )
			Kopete::PluginManager::self()->setPluginEnabled( args->arg( i ), true );
	}
	*/

	// Prevent plugins from loading? (--disable=foo,bar)
	QStringList disableArgs = QStringList::split( ',', args->getOption( "disable" ) );
	for ( QStringList::ConstIterator it = disableArgs.begin(); it != disableArgs.end(); ++it )
	{
		showConfigDialog = false;
		Kopete::PluginManager::self()->setPluginEnabled( *it, false );
	}

	// Load some plugins exclusively? (--load-plugins=foo,bar)
	if ( args->isSet( "load-plugins" ) )
	{
		config->deleteGroup( "Plugins", true );
		showConfigDialog = false;
		QStringList plugins = QStringList::split( ',', args->getOption( "load-plugins" ) );
		for ( QStringList::ConstIterator it = plugins.begin(); it != plugins.end(); ++it )
			Kopete::PluginManager::self()->setPluginEnabled( *it, true );
	}

	config->sync();

	// Disable plugins altogether? (--noplugins)
	if ( !args->isSet( "plugins" ) )
	{
		// If anybody reenables this I'll get a sword and make a nice chop-suy out
		// of your body :P [mETz - 29.05.2004]
		// This screws up kopeterc because there is no way to get the Plugins group back!
		//config->deleteGroup( "Plugins", true );

		showConfigDialog = false;
		// pretend all plugins were loaded :)
		QTimer::singleShot(0, this, SLOT( slotAllPluginsLoaded() ));
	}
	else
	{
		Kopete::PluginManager::self()->loadAllPlugins();
	}

	connect( Kopete::PluginManager::self(), SIGNAL( allPluginsLoaded() ),
		this, SLOT( slotAllPluginsLoaded() ));

	if( showConfigDialog )
	{
		// No plugins specified. Show the config dialog.
		// FIXME: Although it's a bit stupid it is theoretically possible that a user
		//        explicitly configured Kopete to not load plugins on startup. In this
		//        case we don't want this dialog. We need some other config setting
		//        like a bool hasRunKopeteBefore or so to trigger the loading of the
		//        wizard. Maybe using the last run version number is more useful even
		//        as it also allows for other features. - Martijn
		// FIXME: Of course this is not a too-good GUI because a first-timer would need
		//        some kind of "welcome" dialog or wizard. But for now it's better than
		//        nothing at all. - Martijn
		// FIXME: Possibly we need to influence the showConfigDialog bool based on the
		//        command line arguments processed below. But how exactly? - Martijn
		KAction *action = KopeteStdAction::preferences( 0L );
		action->activate();
		delete action;
	}
}

void KopeteApplication::slotAllPluginsLoaded()
{
	KCmdLineArgs *args = KCmdLineArgs::parsedArgs();

	// --noconnect not specified?
	if ( args->isSet( "connect" )  && KopetePrefs::prefs()->autoConnect() )
		Kopete::AccountManager::self()->connectAll();

	QCStringList connectArgs = args->getOptionList( "autoconnect" );
	for ( QCStringList::ConstIterator i = connectArgs.begin(); i != connectArgs.end(); ++i )
	{
		QString id = QString::fromLatin1( *i );

		QRegExp rx( QString::fromLatin1( "([^\\|]*)\\|\\|(.*)" ) );
		rx.search( id );
		QString protocolId = rx.cap( 1 );
		QString accountId = rx.cap( 2 );

		if ( accountId.isEmpty() )
		{
			if ( protocolId.isEmpty() )
				accountId = id;
			else
				continue;
		}

		QPtrListIterator<Kopete::Account> it( Kopete::AccountManager::self()->accounts() );
		Kopete::Account *account;
		while ( ( account = it.current() ) != 0 )
		{
			++it;

			if ( ( account->accountId() == accountId ) )
			{
				if ( protocolId.isEmpty() || account->protocol()->pluginId() == protocolId )
				{
					account->connect();
					break;
				}
			}
		}
	}

	// Parse any passed URLs/files
	handleURLArgs();
}

int KopeteApplication::newInstance()
{
	kdDebug(14000) << k_funcinfo << endl;
	handleURLArgs();

	/**
	 * The following three lines work around a problem that
	 * Kopete has since it has multiple main windows so
	 * qapp->mainWidget() returns 0, which breaks the normal
	 * KUniqueApplication::newInstance() behavior that raises
	 * the window when we run a new instance.
	 *
	 * 1. Set the main widget to the contact list window
	 * 2. Call KUniqueApplication::newInstance()
	 * 3. Set the main widget back to 0
	 *
	 * This little workaround fixes the problem. -Matt
	 */

	setMainWidget( m_mainWindow );
	int kUniqAppReturnCode = KUniqueApplication::newInstance();
	setMainWidget( 0L );

	return kUniqAppReturnCode;
}

void KopeteApplication::handleURLArgs()
{
	KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
	kdDebug(14000) << k_funcinfo << "called with " << args->count() <<
		" arguments to handle." << endl;

	if ( args->count() > 0 )
	{
		for ( int i = 0; i < args->count(); i++ )
		{
			KURL u( args->url( i ) );
			if ( !u.isValid() )
				continue;

			Kopete::MimeTypeHandler::dispatchURL( u );
		} // END for()
	} // END args->count() > 0
}

void KopeteApplication::quitKopete()
{
	kdDebug( 14000 ) << k_funcinfo << endl;

	if ( !m_isShuttingDown )
	{
		m_isShuttingDown = true;

#if KDE_VERSION < KDE_MAKE_VERSION( 3, 1, 90 )
		// When we close Kopete through KSystemTray, kdelibs will close all open
		// windows first. However, despite the destructive close the main window
		// is _NOT_ yet deleted at this point (it's a scheduled deleteLater()
		// call).
		// Due to a bug in KMainWindow prior to KDE 3.2 calling close() a second
		// time also derefs KApplication a second time, which causes a premature
		// call to KApplication::quit(), so we never go through the plugin
		// manager's shutdown process.
		// Unfortunately we can't assume close() ever being called though,
		// because the code paths not using the system tray still need this.
		// As a workaround we schedule a call to quitKopete() through a timer,
		// so the event loop is processed and the window is already deleted.
		// - Martijn
		QTimer::singleShot( 0, this, SLOT( quitKopete() ) );
		return;
#endif
	}

	if ( !m_mainWindow.isNull() )
		m_mainWindow->close();

	// save the contact list now, just in case a change was made very recently
	// and it hasn't autosaved yet
	Kopete::ContactList::self()->save();
	Kopete::AccountManager::self()->save();

	//unload plugins and shutdown
	Kopete::PluginManager::self()->shutdown();
}

void KopeteApplication::commitData( QSessionManager &sm )
{
	m_isShuttingDown = true;
	KUniqueApplication::commitData( sm );
}

#include "kopeteapplication.moc"
// vim: set noet ts=4 sts=4 sw=4:
<commit_msg>Preload the addressbook, because loading it at an arbitrary point (MCLVI init) during startup causes us to enter the event loop, which breaks many things.<commit_after>/*
    kopete.cpp

    Kopete Instant Messenger Main Class

    Copyright (c) 2001-2002  by Duncan Mac-Vicar Prett   <duncan@kde.org>
    Copyright (c) 2002-2003  by Martijn Klingens         <klingens@kde.org>

    Kopete    (c) 2001-2003  by the Kopete developers    <kopete-devel@kde.org>

    *************************************************************************
    *                                                                       *
    * This program is free software; you can redistribute it and/or modify  *
    * it under the terms of the GNU General Public License as published by  *
    * the Free Software Foundation; either version 2 of the License, or     *
    * (at your option) any later version.                                   *
    *                                                                       *
    *************************************************************************
*/

#include "kopeteapplication.h"

#include <qtimer.h>
#include <qregexp.h>

#include <kconfig.h>
#include <kdebug.h>
#include <klocale.h>
#include <kcmdlineargs.h>
#include <kmessagebox.h>

#include "kabcpersistence.h"
#include "kopeteaccount.h"
#include "kopeteaccountmanager.h"
#include "kopetecommandhandler.h"
#include "kopetecontactlist.h"
#include "kopeteglobal.h"
#include "kopetemimesourcefactory.h"
#include "kopetemimetypehandler.h"
#include "kopetepluginmanager.h"
#include "kopeteprotocol.h"
#include "kopetestdaction.h"
#include "kopeteuiglobal.h"
#include "kopetewindow.h"
#include "kopeteprefs.h"
#include "kopeteviewmanager.h"

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

KopeteApplication::KopeteApplication()
: KUniqueApplication( true, true, true )
{
	m_isShuttingDown = false;
	m_mainWindow = new KopeteWindow( 0, "mainWindow" );

	/* KMainWindow is very broken from our point of view - it deref()'s the app
	 * when the last visible KMainWindow is destroyed. This is broken for a number
	 * of reasons, not least because it can happen more than once within a single
	 * instance of Kopete. Also, our main window is hidden when it's in the tray,
	 * and closing the last chatwindow when in that state can cause the app to quit.
	 *
	 * KopeteApplication's reference counting scheme is different to that of a normal
	 * KDE application. It works as follows: the Kopete::PluginManager has a reference
	 * to the application. No windows ever call KMainWindow::closeEvent, so KMainWindow
	 * doesn't stupidly deref() our application. This ensures that the application
	 * reference counting still works properly, and that the application terminates
	 * neither too early (bug 75805) nor too late (bug 71657). - Richard
	 */

	// KApplication sets the reference count to 1 on startup. Kopete::PluginManager has a
	// reference to us once created, so create it and drop our own reference.
	Kopete::PluginManager::self();
	deref();

	Kopete::UI::Global::setMainWidget( m_mainWindow );

	/*
	 * FIXME: This is a workaround for a quite odd problem:
	 * When starting up kopete and the msn plugin gets loaded it can bring up
	 * a messagebox, in case the msg configuration is missing. This messagebox
	 * will result in a QApplication::enter_loop() call, an event loop is
	 * created. At this point however the loop_level is 0, because this is all
	 * still inside the KopeteApplication constructor, before the exec() call from main.
	 * When the messagebox is finished the loop_level will drop down to zero and
	 * QApplication thinks the application shuts down (this is usually the case
	 * when the loop_level goes down to zero) . So it emits aboutToQuit(), to
	 * which KApplication is connected and re-emits shutdown() , to which again
	 * KMainWindow (a KopeteWindow instance exists already) is connected. KMainWindow's
	 * shuttingDown() slot calls queryExit() which results in KopeteWindow::queryExit()
	 * calling unloadPlugins() . This of course is wrong and just shouldn't happen.
	 * The workaround is to simply delay the initialization of all this to a point
	 * where the loop_level is already > 0 . That is why I moved all the code from
	 * the constructor to the initialize() method and added this single-shot-timer
	 * setup. (Simon)
	 *
	 * Additionally, it makes the GUI appear less 'blocking' during startup, so
	 * there is a secondary benefit as well here. (Martijn)
	 */
	QTimer::singleShot( 0, this, SLOT( slotLoadPlugins() ) );

	m_mimeFactory = new Kopete::MimeSourceFactory;
	QMimeSourceFactory::addFactory( m_mimeFactory );

	//Create the emoticon installer
	m_emoticonHandler = new Kopete::EmoticonMimeTypeHandler;
}

KopeteApplication::~KopeteApplication()
{
	kdDebug( 14000 ) << k_funcinfo << endl;

	delete m_mainWindow;
	delete m_emoticonHandler;
	delete m_mimeFactory;
	//kdDebug( 14000 ) << k_funcinfo << "Done" << endl;
}

void KopeteApplication::slotLoadPlugins()
{
	// we have to load the address book early, because calling this enters the Qt event loop when there are remote resources.
	// The plugin manager is written with the assumption that Kopete will not reenter the event loop during plugin load,
	// otherwise lots of things break as plugins are loaded, then contacts are added to incompletely initialised MCLVIs
	Kopete::KABCPersistence::self()->addressBook();

	//Create the command handler (looks silly)
	Kopete::CommandHandler::commandHandler();

	//Create the view manager
	KopeteViewManager::viewManager();

	Kopete::AccountManager::self()->load();
	Kopete::ContactList::self()->load();

	KConfig *config = KGlobal::config();

	// Parse command-line arguments
	KCmdLineArgs *args = KCmdLineArgs::parsedArgs();

	bool showConfigDialog = false;

	config->setGroup( "Plugins" );

	/* FIXME: This is crap, if something purged that groups but your accounts
	 * are still working kopete will load the necessary plugins but still show the
	 * stupid accounts dialog (of course empty at that time because account data
	 * gets loaded later on). [mETz - 29.05.2004]
	 */
	if ( !config->hasGroup( "Plugins" ) )
		showConfigDialog = true;

	// Listen to arguments
	/*
	// TODO: conflicts with emoticon installer and the general meaning
	// of %U in kopete.desktop
	if ( args->count() > 0 )
	{
		showConfigDialog = false;
		for ( int i = 0; i < args->count(); i++ )
			Kopete::PluginManager::self()->setPluginEnabled( args->arg( i ), true );
	}
	*/

	// Prevent plugins from loading? (--disable=foo,bar)
	QStringList disableArgs = QStringList::split( ',', args->getOption( "disable" ) );
	for ( QStringList::ConstIterator it = disableArgs.begin(); it != disableArgs.end(); ++it )
	{
		showConfigDialog = false;
		Kopete::PluginManager::self()->setPluginEnabled( *it, false );
	}

	// Load some plugins exclusively? (--load-plugins=foo,bar)
	if ( args->isSet( "load-plugins" ) )
	{
		config->deleteGroup( "Plugins", true );
		showConfigDialog = false;
		QStringList plugins = QStringList::split( ',', args->getOption( "load-plugins" ) );
		for ( QStringList::ConstIterator it = plugins.begin(); it != plugins.end(); ++it )
			Kopete::PluginManager::self()->setPluginEnabled( *it, true );
	}

	config->sync();

	// Disable plugins altogether? (--noplugins)
	if ( !args->isSet( "plugins" ) )
	{
		// If anybody reenables this I'll get a sword and make a nice chop-suy out
		// of your body :P [mETz - 29.05.2004]
		// This screws up kopeterc because there is no way to get the Plugins group back!
		//config->deleteGroup( "Plugins", true );

		showConfigDialog = false;
		// pretend all plugins were loaded :)
		QTimer::singleShot(0, this, SLOT( slotAllPluginsLoaded() ));
	}
	else
	{
		Kopete::PluginManager::self()->loadAllPlugins();
	}

	connect( Kopete::PluginManager::self(), SIGNAL( allPluginsLoaded() ),
		this, SLOT( slotAllPluginsLoaded() ));

	if( showConfigDialog )
	{
		// No plugins specified. Show the config dialog.
		// FIXME: Although it's a bit stupid it is theoretically possible that a user
		//        explicitly configured Kopete to not load plugins on startup. In this
		//        case we don't want this dialog. We need some other config setting
		//        like a bool hasRunKopeteBefore or so to trigger the loading of the
		//        wizard. Maybe using the last run version number is more useful even
		//        as it also allows for other features. - Martijn
		// FIXME: Of course this is not a too-good GUI because a first-timer would need
		//        some kind of "welcome" dialog or wizard. But for now it's better than
		//        nothing at all. - Martijn
		// FIXME: Possibly we need to influence the showConfigDialog bool based on the
		//        command line arguments processed below. But how exactly? - Martijn
		KAction *action = KopeteStdAction::preferences( 0L );
		action->activate();
		delete action;
	}
}

void KopeteApplication::slotAllPluginsLoaded()
{
	KCmdLineArgs *args = KCmdLineArgs::parsedArgs();

	// --noconnect not specified?
	if ( args->isSet( "connect" )  && KopetePrefs::prefs()->autoConnect() )
		Kopete::AccountManager::self()->connectAll();

	QCStringList connectArgs = args->getOptionList( "autoconnect" );
	for ( QCStringList::ConstIterator i = connectArgs.begin(); i != connectArgs.end(); ++i )
	{
		QString id = QString::fromLatin1( *i );

		QRegExp rx( QString::fromLatin1( "([^\\|]*)\\|\\|(.*)" ) );
		rx.search( id );
		QString protocolId = rx.cap( 1 );
		QString accountId = rx.cap( 2 );

		if ( accountId.isEmpty() )
		{
			if ( protocolId.isEmpty() )
				accountId = id;
			else
				continue;
		}

		QPtrListIterator<Kopete::Account> it( Kopete::AccountManager::self()->accounts() );
		Kopete::Account *account;
		while ( ( account = it.current() ) != 0 )
		{
			++it;

			if ( ( account->accountId() == accountId ) )
			{
				if ( protocolId.isEmpty() || account->protocol()->pluginId() == protocolId )
				{
					account->connect();
					break;
				}
			}
		}
	}

	// Parse any passed URLs/files
	handleURLArgs();
}

int KopeteApplication::newInstance()
{
	kdDebug(14000) << k_funcinfo << endl;
	handleURLArgs();

	/**
	 * The following three lines work around a problem that
	 * Kopete has since it has multiple main windows so
	 * qapp->mainWidget() returns 0, which breaks the normal
	 * KUniqueApplication::newInstance() behavior that raises
	 * the window when we run a new instance.
	 *
	 * 1. Set the main widget to the contact list window
	 * 2. Call KUniqueApplication::newInstance()
	 * 3. Set the main widget back to 0
	 *
	 * This little workaround fixes the problem. -Matt
	 */

	setMainWidget( m_mainWindow );
	int kUniqAppReturnCode = KUniqueApplication::newInstance();
	setMainWidget( 0L );

	return kUniqAppReturnCode;
}

void KopeteApplication::handleURLArgs()
{
	KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
	kdDebug(14000) << k_funcinfo << "called with " << args->count() <<
		" arguments to handle." << endl;

	if ( args->count() > 0 )
	{
		for ( int i = 0; i < args->count(); i++ )
		{
			KURL u( args->url( i ) );
			if ( !u.isValid() )
				continue;

			Kopete::MimeTypeHandler::dispatchURL( u );
		} // END for()
	} // END args->count() > 0
}

void KopeteApplication::quitKopete()
{
	kdDebug( 14000 ) << k_funcinfo << endl;

	if ( !m_isShuttingDown )
	{
		m_isShuttingDown = true;

#if KDE_VERSION < KDE_MAKE_VERSION( 3, 1, 90 )
		// When we close Kopete through KSystemTray, kdelibs will close all open
		// windows first. However, despite the destructive close the main window
		// is _NOT_ yet deleted at this point (it's a scheduled deleteLater()
		// call).
		// Due to a bug in KMainWindow prior to KDE 3.2 calling close() a second
		// time also derefs KApplication a second time, which causes a premature
		// call to KApplication::quit(), so we never go through the plugin
		// manager's shutdown process.
		// Unfortunately we can't assume close() ever being called though,
		// because the code paths not using the system tray still need this.
		// As a workaround we schedule a call to quitKopete() through a timer,
		// so the event loop is processed and the window is already deleted.
		// - Martijn
		QTimer::singleShot( 0, this, SLOT( quitKopete() ) );
		return;
#endif
	}

	if ( !m_mainWindow.isNull() )
		m_mainWindow->close();

	// save the contact list now, just in case a change was made very recently
	// and it hasn't autosaved yet
	Kopete::ContactList::self()->save();
	Kopete::AccountManager::self()->save();

	//unload plugins and shutdown
	Kopete::PluginManager::self()->shutdown();
}

void KopeteApplication::commitData( QSessionManager &sm )
{
	m_isShuttingDown = true;
	KUniqueApplication::commitData( sm );
}

#include "kopeteapplication.moc"
// vim: set noet ts=4 sts=4 sw=4:
<|endoftext|>