<commit_before>/******************************************************************************\
* File:          test.cpp
* Purpose:       Implementation for wxextension cpp unit testing
* Author:        Anton van Wezenbeek
* RCS-ID:        $Id: test.cpp 450 2009-03-11 20:02:41Z antonvw $
* Created:       za 17 jan 2009 11:51:20 CET
*
* Copyright (c) 2009 Anton van Wezenbeek
* All rights are reserved. Reproduction in whole or part is prohibited
* without the written consent of the copyright owner.
\******************************************************************************/

#include <TestCaller.h>
#include "test.h"

void exTestFixture::setUp()
{
  m_Config = new exConfig("test.cfg", wxCONFIG_USE_LOCAL_FILE);
  m_File = new exFile("test.h");
  m_FileName = new exFileName("test.h");
  m_FileNameStatistics = new exFileNameStatistics("test.h");
  m_Lexer = new exLexer();
  m_Lexers = new exLexers(exFileName("../../data/lexers.xml"));
  m_RCS = new exRCS();
  m_Stat = new exStat("test.h");
  m_Statistics = new exStatistics<long>();
  m_TextFile = new exTextFile(exFileName("test.h"), m_Config, m_Lexers);
  m_Tool = new exTool(ID_TOOL_REPORT_COUNT);
}

void exTestFixture::testConstructors()
{
  CPPUNIT_ASSERT(m_File != NULL);
}

void exTestFixture::testMethods()
{
  // test exConfig
  CPPUNIT_ASSERT(m_Config->Get("keystring", "val") == "val");
  CPPUNIT_ASSERT(m_Config->Get("keylong", 12) == 12);
  CPPUNIT_ASSERT(m_Config->GetBool("keybool", true));
  CPPUNIT_ASSERT(m_Config->GetFindReplaceData() != NULL);
  m_Config->Set("keystring", "val2");
  CPPUNIT_ASSERT(m_Config->Get("keystring", "val") == "val2");
  m_Config->Set("keylong", 15);
  CPPUNIT_ASSERT(m_Config->Get("keylong", 7) == 15);
  m_Config->SetBool("keybool", false);
  CPPUNIT_ASSERT(m_Config->GetBool("keybool", true) == false);
  m_Config->Toggle("keybool");
  CPPUNIT_ASSERT(m_Config->GetBool("keybool", false));

  // test exFile
  CPPUNIT_ASSERT(m_File->GetStat().IsOk());
  CPPUNIT_ASSERT(m_File->GetStat().GetFullPath() == m_File->GetFileName().GetFullPath());
  // The fullpath should be normalized, test it.
  CPPUNIT_ASSERT(m_File->GetFileName().GetFullPath() != "test.h");
  CPPUNIT_ASSERT(!m_File->GetStat().IsReadOnly());
  CPPUNIT_ASSERT(!m_File->CheckSyncNeeded());
  CPPUNIT_ASSERT(!m_File->GetStat().IsReadOnly());
  CPPUNIT_ASSERT(m_File->FileOpen(exFileName("test.bin")));
  wxString* buffer = m_File->Read();
  CPPUNIT_ASSERT(buffer != NULL);
  CPPUNIT_ASSERT(buffer->size() == 40);
  delete buffer;

  // test exFileName
  CPPUNIT_ASSERT(m_FileName->GetLexer().GetScintillaLexer().empty());
  CPPUNIT_ASSERT(m_FileName->GetStat().IsOk());
  m_FileName->Assign("xxx");
  m_FileName->GetStat().Update("xxx");
  CPPUNIT_ASSERT(!m_FileName->GetStat().IsOk());

  // test exFileNameStatistics
  CPPUNIT_ASSERT(m_FileNameStatistics->Get().empty());
  CPPUNIT_ASSERT(m_FileNameStatistics->Get("xx") == 0);

  // test exLexer
  *m_Lexer = m_Lexers->FindByText("// this is a cpp comment text");
  CPPUNIT_ASSERT(m_Lexer->GetScintillaLexer().empty()); // we have no lexers
  m_Lexer->SetKeywords("test11 test21:1 test31:1 test12:2 test22:2");
  CPPUNIT_ASSERT(m_Lexer->IsKeyword("test11"));
  CPPUNIT_ASSERT(m_Lexer->IsKeyword("test21"));
  CPPUNIT_ASSERT(m_Lexer->IsKeyword("test12"));
  CPPUNIT_ASSERT(m_Lexer->IsKeyword("test22"));
  CPPUNIT_ASSERT(m_Lexer->KeywordStartsWith("te"));
  CPPUNIT_ASSERT(!m_Lexer->KeywordStartsWith("xx"));
  CPPUNIT_ASSERT(!m_Lexer->GetKeywords().empty());
  CPPUNIT_ASSERT(!m_Lexer->GetKeywordsSet().empty());

  // test exLexers
  CPPUNIT_ASSERT(m_Lexers->Read());
  *m_Lexer = m_Lexers->FindByText("// this is a cpp comment text");
  CPPUNIT_ASSERT(m_Lexer->GetScintillaLexer() == "cpp");
  CPPUNIT_ASSERT(m_Lexers->FindByFileName(wxFileName("test.h")).GetScintillaLexer() == "cpp");
  CPPUNIT_ASSERT(m_Lexers->FindByName("cpp").GetScintillaLexer() == "cpp");
  CPPUNIT_ASSERT(m_Lexers->Count() > 0);
  CPPUNIT_ASSERT(!m_Lexers->BuildWildCards(wxFileName("test.h")).empty());
  CPPUNIT_ASSERT(!m_Lexers->GetIndicators().empty());
  CPPUNIT_ASSERT(!m_Lexers->GetMarkers().empty());
  CPPUNIT_ASSERT(!m_Lexers->GetStyles().empty());
  CPPUNIT_ASSERT(!m_Lexers->GetStylesHex().empty());
  CPPUNIT_ASSERT(!m_Lexer->GetAssociations().empty());
  CPPUNIT_ASSERT(!m_Lexer->GetColourings().empty());
  CPPUNIT_ASSERT(!m_Lexer->GetCommentBegin().empty());
  CPPUNIT_ASSERT(!m_Lexer->GetCommentBegin2().empty());
  CPPUNIT_ASSERT(!m_Lexer->GetCommentEnd().empty());
  CPPUNIT_ASSERT(!m_Lexer->GetCommentEnd2().empty());
  CPPUNIT_ASSERT(!m_Lexer->GetKeywords().empty());
  CPPUNIT_ASSERT(!m_Lexer->GetKeywordsSet().empty());
  CPPUNIT_ASSERT(!m_Lexer->GetKeywordsString().empty());
  CPPUNIT_ASSERT(!m_Lexer->GetProperties().empty());
  CPPUNIT_ASSERT(m_Lexer->IsKeyword("class"));
  CPPUNIT_ASSERT(m_Lexer->IsKeyword("const"));
  CPPUNIT_ASSERT(m_Lexer->KeywordStartsWith("cla"));
  CPPUNIT_ASSERT(!m_Lexer->KeywordStartsWith("xxx"));
  CPPUNIT_ASSERT(!m_Lexer->MakeComment("test", true).empty());
  CPPUNIT_ASSERT(m_Lexer->UsableCharactersPerLine() == 74); // 80 - 4 (comments) - 2 (spaces)

  // test exRCS
  CPPUNIT_ASSERT(m_RCS->GetAuthor().empty());
  CPPUNIT_ASSERT(m_RCS->GetDescription().empty());
  CPPUNIT_ASSERT(m_RCS->GetUser().empty());

  // test exStat
  CPPUNIT_ASSERT(!m_Stat->IsLink());
  CPPUNIT_ASSERT(m_Stat->IsOk());
  CPPUNIT_ASSERT(!m_Stat->IsReadOnly());
  CPPUNIT_ASSERT(m_Stat->Update("testlink"));
//  CPPUNIT_ASSERT(m_Stat->IsLink());

  // test exStatistics
  m_Statistics->Inc("test");
  CPPUNIT_ASSERT(m_Statistics->Get("test") == 1);
  m_Statistics->Inc("test");
  CPPUNIT_ASSERT(m_Statistics->Get("test") == 2);
  m_Statistics->Set("test", 13);
  CPPUNIT_ASSERT(m_Statistics->Get("test") == 13);
  m_Statistics->Dec("test");
  CPPUNIT_ASSERT(m_Statistics->Get("test") == 12);
  m_Statistics->Inc("test2");
  CPPUNIT_ASSERT(m_Statistics->Get("test2") == 1);
  m_Statistics->Clear();
  CPPUNIT_ASSERT(m_Statistics->GetItems().empty());

  // test exTextFile
  CPPUNIT_ASSERT(m_TextFile->RunTool(ID_TOOL_REPORT_COUNT));
  CPPUNIT_ASSERT(!m_TextFile->GetStatistics().GetElements().GetItems().empty());
  CPPUNIT_ASSERT(!m_TextFile->IsOpened()); // file should be closed after running tool

  CPPUNIT_ASSERT(m_TextFile->RunTool(ID_TOOL_REPORT_COUNT)); // do the same test
  CPPUNIT_ASSERT(!m_TextFile->GetStatistics().GetElements().GetItems().empty());
  CPPUNIT_ASSERT(!m_TextFile->IsOpened()); // file should be closed after running tool

  CPPUNIT_ASSERT(m_TextFile->RunTool(ID_TOOL_REPORT_HEADER));
  CPPUNIT_ASSERT(m_TextFile->GetTool().GetId() == ID_TOOL_REPORT_HEADER);
//wxLogMessage(m_TextFile->GetStatistics().Get() + m_TextFile->GetRCS().GetDescription());
//  CPPUNIT_ASSERT(m_TextFile->GetRCS().GetDescription() ==
//    "Declaration of classes for wxextension cpp unit testing");

  CPPUNIT_ASSERT(m_TextFile->RunTool(ID_TOOL_REPORT_KEYWORD));
//  CPPUNIT_ASSERT(!m_TextFile->GetStatistics().GetKeywords().GetItems().empty());

  // test exTool
  CPPUNIT_ASSERT(m_Tool->IsStatisticsType() > 0);
}

void exTestFixture::testTiming()
{
  exFile file("test.h");

  CPPUNIT_ASSERT(file.IsOpened());

  wxStopWatch sw;

  const int max = 10000;

  for (int i = 0; i < max; i++)
  {
    wxString* buffer = file.Read();
    CPPUNIT_ASSERT(buffer != NULL);
    delete buffer;
  }

  const long exfile_read = sw.Time();

  sw.Start();

  wxFile wxfile("test.h");

  for (int j = 0; j < max; j++)
  {
    char* charbuffer = new char[wxfile.Length()];
    wxfile.Read(charbuffer, wxfile.Length());
    wxString* buffer = new wxString(charbuffer, wxfile.Length());
    delete charbuffer;
    delete buffer;
  }

  const long file_read = sw.Time();

  printf(
    "exFile::Read:%ld wxFile::Read:%ld\n",
    exfile_read,
    file_read);
}

void exTestFixture::testTimingAttrib()
{
  const int max = 1000;

  wxStopWatch sw;

  const exFileName exfile("test.h");

  int checked = 0;

  for (int i = 0; i < max; i++)
  {
    checked += exfile.GetStat().IsReadOnly();
  }

  const long exfile_time = sw.Time();

  sw.Start();

  const wxFileName file("test.h");

  for (int j = 0; j < max; j++)
  {
    checked += file.IsFileWritable();
  }

  const long file_time = sw.Time();

  printf(
    "exFileName::IsReadOnly:%ld wxFileName::IsFileWritable:%ld\n",
    exfile_time,
    file_time);
}

void exTestFixture::testTimingConfig()
{
  const int max = 100000;

  wxStopWatch sw;

  for (int i = 0; i < max; i++)
  {
    m_Config->Get("test", 0);
  }

  const long exconfig = sw.Time();

  sw.Start();

  for (int j = 0; j < max; j++)
  {
    m_Config->Read("test", 0l);
  }

  const long config = sw.Time();

  printf(
    "exConfig::Get:%ld wxConfig::Read:%ld\n",
    exconfig,
    config);
}

void exTestFixture::tearDown()
{
}

exTestSuite::exTestSuite()
  : CppUnit::TestSuite("wxextension test suite")
{
  // Add the tests.
  addTest(new CppUnit::TestCaller<exTestFixture>(
    "testConstructors",
    &exTestFixture::testConstructors));

  addTest(new CppUnit::TestCaller<exTestFixture>(
    "testMethods",
    &exTestFixture::testMethods));

  addTest(new CppUnit::TestCaller<exTestFixture>(
    "testTiming",
    &exTestFixture::testTiming));

  addTest(new CppUnit::TestCaller<exTestFixture>(
    "testTimingAttrib",
    &exTestFixture::testTimingAttrib));

  addTest(new CppUnit::TestCaller<exTestFixture>(
    "testTimingConfig",
    &exTestFixture::testTimingConfig));
}
<commit_msg>add test for new exHeader<commit_after>/******************************************************************************\
* File:          test.cpp
* Purpose:       Implementation for wxextension cpp unit testing
* Author:        Anton van Wezenbeek
* RCS-ID:        $Id: test.cpp 450 2009-03-11 20:02:41Z antonvw $
* Created:       za 17 jan 2009 11:51:20 CET
*
* Copyright (c) 2009 Anton van Wezenbeek
* All rights are reserved. Reproduction in whole or part is prohibited
* without the written consent of the copyright owner.
\******************************************************************************/

#include <TestCaller.h>
#include "test.h"

void exTestFixture::setUp()
{
  m_Config = new exConfig("test.cfg", wxCONFIG_USE_LOCAL_FILE);
  m_File = new exFile("test.h");
  m_FileName = new exFileName("test.h");
  m_FileNameStatistics = new exFileNameStatistics("test.h");
  m_Lexer = new exLexer();
  m_Lexers = new exLexers(exFileName("../../data/lexers.xml"));
  m_RCS = new exRCS();
  m_Stat = new exStat("test.h");
  m_Statistics = new exStatistics<long>();
  m_TextFile = new exTextFile(exFileName("test.h"), m_Config, m_Lexers);
  m_Tool = new exTool(ID_TOOL_REPORT_COUNT);
}

void exTestFixture::testConstructors()
{
  CPPUNIT_ASSERT(m_File != NULL);
}

void exTestFixture::testMethods()
{
  // test exConfig
  CPPUNIT_ASSERT(m_Config->Get("keystring", "val") == "val");
  CPPUNIT_ASSERT(m_Config->Get("keylong", 12) == 12);
  CPPUNIT_ASSERT(m_Config->GetBool("keybool", true));
  CPPUNIT_ASSERT(m_Config->GetFindReplaceData() != NULL);
  m_Config->Set("keystring", "val2");
  CPPUNIT_ASSERT(m_Config->Get("keystring", "val") == "val2");
  m_Config->Set("keylong", 15);
  CPPUNIT_ASSERT(m_Config->Get("keylong", 7) == 15);
  m_Config->SetBool("keybool", false);
  CPPUNIT_ASSERT(m_Config->GetBool("keybool", true) == false);
  m_Config->Toggle("keybool");
  CPPUNIT_ASSERT(m_Config->GetBool("keybool", false));

  // test exFile
  CPPUNIT_ASSERT(m_File->GetStat().IsOk());
  CPPUNIT_ASSERT(m_File->GetStat().GetFullPath() == m_File->GetFileName().GetFullPath());
  // The fullpath should be normalized, test it.
  CPPUNIT_ASSERT(m_File->GetFileName().GetFullPath() != "test.h");
  CPPUNIT_ASSERT(!m_File->GetStat().IsReadOnly());
  CPPUNIT_ASSERT(!m_File->CheckSyncNeeded());
  CPPUNIT_ASSERT(!m_File->GetStat().IsReadOnly());
  CPPUNIT_ASSERT(m_File->FileOpen(exFileName("test.bin")));
  wxString* buffer = m_File->Read();
  CPPUNIT_ASSERT(buffer != NULL);
  CPPUNIT_ASSERT(buffer->size() == 40);
  delete buffer;

  // test exFileName
  CPPUNIT_ASSERT(m_FileName->GetLexer().GetScintillaLexer().empty());
  CPPUNIT_ASSERT(m_FileName->GetStat().IsOk());
  m_FileName->Assign("xxx");
  m_FileName->GetStat().Update("xxx");
  CPPUNIT_ASSERT(!m_FileName->GetStat().IsOk());

  // test exFileNameStatistics
  CPPUNIT_ASSERT(m_FileNameStatistics->Get().empty());
  CPPUNIT_ASSERT(m_FileNameStatistics->Get("xx") == 0);

  // test exLexer
  *m_Lexer = m_Lexers->FindByText("// this is a cpp comment text");
  CPPUNIT_ASSERT(m_Lexer->GetScintillaLexer().empty()); // we have no lexers
  m_Lexer->SetKeywords("test11 test21:1 test31:1 test12:2 test22:2");
  CPPUNIT_ASSERT(m_Lexer->IsKeyword("test11"));
  CPPUNIT_ASSERT(m_Lexer->IsKeyword("test21"));
  CPPUNIT_ASSERT(m_Lexer->IsKeyword("test12"));
  CPPUNIT_ASSERT(m_Lexer->IsKeyword("test22"));
  CPPUNIT_ASSERT(m_Lexer->KeywordStartsWith("te"));
  CPPUNIT_ASSERT(!m_Lexer->KeywordStartsWith("xx"));
  CPPUNIT_ASSERT(!m_Lexer->GetKeywords().empty());
  CPPUNIT_ASSERT(!m_Lexer->GetKeywordsSet().empty());

  // test exLexers
  CPPUNIT_ASSERT(m_Lexers->Read());
  *m_Lexer = m_Lexers->FindByText("// this is a cpp comment text");
  CPPUNIT_ASSERT(m_Lexer->GetScintillaLexer() == "cpp");
  CPPUNIT_ASSERT(m_Lexers->FindByFileName(wxFileName("test.h")).GetScintillaLexer() == "cpp");
  CPPUNIT_ASSERT(m_Lexers->FindByName("cpp").GetScintillaLexer() == "cpp");
  CPPUNIT_ASSERT(m_Lexers->Count() > 0);
  CPPUNIT_ASSERT(!m_Lexers->BuildWildCards(wxFileName("test.h")).empty());
  CPPUNIT_ASSERT(!m_Lexers->GetIndicators().empty());
  CPPUNIT_ASSERT(!m_Lexers->GetMarkers().empty());
  CPPUNIT_ASSERT(!m_Lexers->GetStyles().empty());
  CPPUNIT_ASSERT(!m_Lexers->GetStylesHex().empty());
  CPPUNIT_ASSERT(!m_Lexer->GetAssociations().empty());
  CPPUNIT_ASSERT(!m_Lexer->GetColourings().empty());
  CPPUNIT_ASSERT(!m_Lexer->GetCommentBegin().empty());
  CPPUNIT_ASSERT(!m_Lexer->GetCommentBegin2().empty());
  CPPUNIT_ASSERT(!m_Lexer->GetCommentEnd().empty());
  CPPUNIT_ASSERT(!m_Lexer->GetCommentEnd2().empty());
  CPPUNIT_ASSERT(!m_Lexer->GetKeywords().empty());
  CPPUNIT_ASSERT(!m_Lexer->GetKeywordsSet().empty());
  CPPUNIT_ASSERT(!m_Lexer->GetKeywordsString().empty());
  CPPUNIT_ASSERT(!m_Lexer->GetProperties().empty());
  CPPUNIT_ASSERT(m_Lexer->IsKeyword("class"));
  CPPUNIT_ASSERT(m_Lexer->IsKeyword("const"));
  CPPUNIT_ASSERT(m_Lexer->KeywordStartsWith("cla"));
  CPPUNIT_ASSERT(!m_Lexer->KeywordStartsWith("xxx"));
  CPPUNIT_ASSERT(!m_Lexer->MakeComment("test", true).empty());
  CPPUNIT_ASSERT(m_Lexer->UsableCharactersPerLine() == 74); // 80 - 4 (comments) - 2 (spaces)

  // test exRCS
  CPPUNIT_ASSERT(m_RCS->GetAuthor().empty());
  CPPUNIT_ASSERT(m_RCS->GetDescription().empty());
  CPPUNIT_ASSERT(m_RCS->GetUser().empty());

  // test exStat
  CPPUNIT_ASSERT(!m_Stat->IsLink());
  CPPUNIT_ASSERT(m_Stat->IsOk());
  CPPUNIT_ASSERT(!m_Stat->IsReadOnly());
  CPPUNIT_ASSERT(m_Stat->Update("testlink"));
//  CPPUNIT_ASSERT(m_Stat->IsLink());

  // test exStatistics
  m_Statistics->Inc("test");
  CPPUNIT_ASSERT(m_Statistics->Get("test") == 1);
  m_Statistics->Inc("test");
  CPPUNIT_ASSERT(m_Statistics->Get("test") == 2);
  m_Statistics->Set("test", 13);
  CPPUNIT_ASSERT(m_Statistics->Get("test") == 13);
  m_Statistics->Dec("test");
  CPPUNIT_ASSERT(m_Statistics->Get("test") == 12);
  m_Statistics->Inc("test2");
  CPPUNIT_ASSERT(m_Statistics->Get("test2") == 1);
  m_Statistics->Clear();
  CPPUNIT_ASSERT(m_Statistics->GetItems().empty());

  // test exTextFile
  CPPUNIT_ASSERT(m_TextFile->RunTool(ID_TOOL_REPORT_COUNT));
  CPPUNIT_ASSERT(!m_TextFile->GetStatistics().GetElements().GetItems().empty());
  CPPUNIT_ASSERT(!m_TextFile->IsOpened()); // file should be closed after running tool

  CPPUNIT_ASSERT(m_TextFile->RunTool(ID_TOOL_REPORT_COUNT)); // do the same test
  CPPUNIT_ASSERT(!m_TextFile->GetStatistics().GetElements().GetItems().empty());
  CPPUNIT_ASSERT(!m_TextFile->IsOpened()); // file should be closed after running tool

  CPPUNIT_ASSERT(m_TextFile->RunTool(ID_TOOL_REPORT_KEYWORD));
//  CPPUNIT_ASSERT(!m_TextFile->GetStatistics().GetKeywords().GetItems().empty());

  // test exTool
  CPPUNIT_ASSERT(m_Tool->IsStatisticsType() > 0);

  // test various exMethods
  const wxString header = exHeader(m_TextFile->GetFileName(), m_Config, "test");
  CPPUNIT_ASSERT(header.Contains("test"));
}

void exTestFixture::testTiming()
{
  exFile file("test.h");

  CPPUNIT_ASSERT(file.IsOpened());

  wxStopWatch sw;

  const int max = 10000;

  for (int i = 0; i < max; i++)
  {
    wxString* buffer = file.Read();
    CPPUNIT_ASSERT(buffer != NULL);
    delete buffer;
  }

  const long exfile_read = sw.Time();

  sw.Start();

  wxFile wxfile("test.h");

  for (int j = 0; j < max; j++)
  {
    char* charbuffer = new char[wxfile.Length()];
    wxfile.Read(charbuffer, wxfile.Length());
    wxString* buffer = new wxString(charbuffer, wxfile.Length());
    delete charbuffer;
    delete buffer;
  }

  const long file_read = sw.Time();

  printf(
    "exFile::Read:%ld wxFile::Read:%ld\n",
    exfile_read,
    file_read);
}

void exTestFixture::testTimingAttrib()
{
  const int max = 1000;

  wxStopWatch sw;

  const exFileName exfile("test.h");

  int checked = 0;

  for (int i = 0; i < max; i++)
  {
    checked += exfile.GetStat().IsReadOnly();
  }

  const long exfile_time = sw.Time();

  sw.Start();

  const wxFileName file("test.h");

  for (int j = 0; j < max; j++)
  {
    checked += file.IsFileWritable();
  }

  const long file_time = sw.Time();

  printf(
    "exFileName::IsReadOnly:%ld wxFileName::IsFileWritable:%ld\n",
    exfile_time,
    file_time);
}

void exTestFixture::testTimingConfig()
{
  const int max = 100000;

  wxStopWatch sw;

  for (int i = 0; i < max; i++)
  {
    m_Config->Get("test", 0);
  }

  const long exconfig = sw.Time();

  sw.Start();

  for (int j = 0; j < max; j++)
  {
    m_Config->Read("test", 0l);
  }

  const long config = sw.Time();

  printf(
    "exConfig::Get:%ld wxConfig::Read:%ld\n",
    exconfig,
    config);
}

void exTestFixture::tearDown()
{
}

exTestSuite::exTestSuite()
  : CppUnit::TestSuite("wxextension test suite")
{
  // Add the tests.
  addTest(new CppUnit::TestCaller<exTestFixture>(
    "testConstructors",
    &exTestFixture::testConstructors));

  addTest(new CppUnit::TestCaller<exTestFixture>(
    "testMethods",
    &exTestFixture::testMethods));

  addTest(new CppUnit::TestCaller<exTestFixture>(
    "testTiming",
    &exTestFixture::testTiming));

  addTest(new CppUnit::TestCaller<exTestFixture>(
    "testTimingAttrib",
    &exTestFixture::testTimingAttrib));

  addTest(new CppUnit::TestCaller<exTestFixture>(
    "testTimingConfig",
    &exTestFixture::testTimingConfig));
}
<|endoftext|>


<commit_before>// Author: Rene Brun   12/10/2000

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#include "TROOT.h"
#include "THStack.h"
#include "TVirtualPad.h"
#include "TH2.h"

#include <fstream.h>

ClassImp(THStack)

//______________________________________________________________________________
//
//   A THStack is a collection of TH1 (or derived) objects
//   Use THStack::Add to add a new histogram to the list.
//   The THStack owns the objects in the list.
//   By default (if option "nostack" is not specified), histograms will be paint
//   stacked on top of each other.
//   Example;
//      THStack hs("hs","test stacked histograms");
//      TH1F *h1 = new TH1F("h1","test hstack",100,-4,4);
//      h1->FillRandom("gaus",20000);
//      h1->SetFillColor(kRed);
//      hs.Add(h1);
//      TH1F *h2 = new TH1F("h2","test hstack",100,-4,4);
//      h2->FillRandom("gaus",15000);
//      h2->SetFillColor(kBlue);
//      hs.Add(h2);
//      TH1F *h3 = new TH1F("h3","test hstack",100,-4,4);
//      h3->FillRandom("gaus",10000);
//      h3->SetFillColor(kGreen);
//      hs.Add(h3);
//      TCanvas c1("c1","stacked hists",10,10,700,900);
//      c1.Divide(1,2);
//      c1.cd(1);
//      hs.Draw();
//      c1.cd(2);
//      hs->Draw("nostack");
//
//  See a more complex example in $ROOTSYS/tutorials/hstack.C
//
//  Note that picking is supported for all drawing modes.

//______________________________________________________________________________
THStack::THStack(): TNamed()
{
// THStack default constructor

   fHists     = 0;
   fStack     = 0;
   fHistogram = 0;
   fMaximum   = -1111;
   fMinimum   = -1111;
}

//______________________________________________________________________________
THStack::THStack(const char *name, const char *title)
       : TNamed(name,title)
{
// constructor with name and title
   fHists     = 0;
   fStack     = 0;
   fHistogram = 0;
   fMaximum   = -1111;
   fMinimum   = -1111;
}

//______________________________________________________________________________
THStack::~THStack()
{
// THStack destructor

   if (!fHists) return;
   fHists->Delete();
   delete fHists;
   fHists = 0;
   if (fStack) {fStack->Delete(); delete fStack;}
   delete fHistogram;
   fHistogram = 0;
}

//______________________________________________________________________________
void THStack::Add(TH1 *h1)
{
   // add a new histogram to the list
   // Only 1-d histograms currently supported.
   // Note that all histograms in the list must have the same number
   // of channels and the same X axis.

   if (!h1) return;
   if (h1->GetDimension() > 2) {
      Error("Add","THStack supports only 1-d and 2-d histograms");
      return;
   }
   if (!fHists) fHists = new TObjArray();
   fHists->Add(h1);
}

//______________________________________________________________________________
void THStack::Browse(TBrowser *)
{
    Draw();
    gPad->Update();
}

//______________________________________________________________________________
void THStack::BuildStack()
{
//  build sum of all histograms
//  Build a separate list fStack containing the running sum of all histograms

   if (fStack) return;
   Int_t nhists = fHists->GetEntriesFast();
   fStack = new TObjArray(nhists);
   Bool_t add = TH1::AddDirectoryStatus();
   TH1::AddDirectory(kFALSE);
   TH1 *h = (TH1*)fHists->At(0)->Clone();
   fStack->Add(h);
   for (Int_t i=1;i<nhists;i++) {
      h = (TH1*)fHists->At(i)->Clone();
      h->Add((TH1*)fStack->At(i-1));
      fStack->AddAt(h,i);
   }
   TH1::AddDirectory(add);
}

//______________________________________________________________________________
Int_t THStack::DistancetoPrimitive(Int_t px, Int_t py)
{
// Compute distance from point px,py to each graph
//

//*-*- Are we on the axis?
   const Int_t kMaxDiff = 10;
   Int_t distance = 9999;
   if (fHistogram) {
      distance = fHistogram->DistancetoPrimitive(px,py);
      if (distance <= 0) {return distance;}
      if (distance <= 1) {gPad->SetSelected(fHistogram);return distance;}
   }

//*-*- Loop on the list of histograms
   if (!fHists) return distance;
   TH1 *h = 0;
   const char *doption = GetDrawOption();
   Int_t nhists = fHists->GetEntriesFast();
   for (Int_t i=0;i<nhists;i++) {
      h = (TH1*)fHists->At(i);
      if (fStack && !strstr(doption,"nostack")) h = (TH1*)fStack->At(i);
      Int_t dist = h->DistancetoPrimitive(px,py);
      if (dist < kMaxDiff) {
         gPad->SetSelected(fHists->At(i));
         gPad->SetCursor(kPointer);
         return dist;
      }
   }
   return distance;
}

//______________________________________________________________________________
void THStack::Draw(Option_t *option)
{
//*-*-*-*-*-*-*-*-*-*-*Draw this multihist with its current attributes*-*-*-*-*-*-*
//*-*                  ==========================================
//
//   Options to draw histograms  are described in THistPainter::Paint
// By default (if option "nostack" is not specified), histograms will be paint
// stacked on top of each other.

   TString opt = option;
   opt.ToLower();
   if (gPad) {
      if (!gPad->IsEditable()) (gROOT->GetMakeDefCanvas())();
      if (!opt.Contains("same")) {
         //the following statement is necessary in case one attempts to draw
         //a temporary histogram already in the current pad
         if (TestBit(kCanDelete)) gPad->GetListOfPrimitives()->Remove(this);
         gPad->Clear();
      }
   }
   AppendPad(opt.Data());
}

//______________________________________________________________________________
TH1 *THStack::GetHistogram() const
{
//    Returns a pointer to the histogram used to draw the axis
//    Takes into account the two following cases.
//       1- option 'A' was specified in THStack::Draw. Return fHistogram
//       2- user had called TPad::DrawFrame. return pointer to hframe histogram

   if (fHistogram) return fHistogram;
   if (!gPad) return 0;
   gPad->Modified();
   gPad->Update();
   if (fHistogram) return fHistogram;
   TH1 *h1 = (TH1*)gPad->FindObject("hframe");
   return h1;
}

//______________________________________________________________________________
Double_t THStack::GetMaximum(Option_t *option)
{
//  returns the maximum of all added histograms
//  returns the maximum of all histograms if option "nostack".

   TString opt = option;
   opt.ToLower();
   Double_t them=0, themax = -1e300;
   Int_t nhists = fHists->GetEntriesFast();
   TH1 *h;
   if (!opt.Contains("nostack")) {
       BuildStack();
       h = (TH1*)fStack->At(nhists-1);
       themax = h->GetMaximum();
   } else {
      for (Int_t i=0;i<nhists;i++) {
         h = (TH1*)fHists->At(i);
         them = h->GetMaximum();
         if (them > themax) themax = them;
      }
   }
   return themax;
}

//______________________________________________________________________________
Double_t THStack::GetMinimum(Option_t *option)
{
//  returns the minimum of all added histograms
//  returns the minimum of all histograms if option "nostack".

   TString opt = option;
   opt.ToLower();
   Double_t them=0, themin = 1e300;
   Int_t nhists = fHists->GetEntriesFast();
   TH1 *h;
   if (!opt.Contains("nostack")) {
       BuildStack();
       h = (TH1*)fStack->At(nhists-1);
       themin = h->GetMinimum();
   } else {
      for (Int_t i=0;i<nhists;i++) {
         h = (TH1*)fHists->At(i);
         them = h->GetMinimum();
         if (them < themin) themin = them;
      }
   }
   return themin;
}

//______________________________________________________________________________
TAxis *THStack::GetXaxis() const
{
   // Get x axis of the graph.

   if (!gPad) return 0;
   return GetHistogram()->GetXaxis();
}

//______________________________________________________________________________
TAxis *THStack::GetYaxis() const
{
   // Get y axis of the graph.

   if (!gPad) return 0;
   return GetHistogram()->GetYaxis();
}

//______________________________________________________________________________
void THStack::ls(Option_t *option) const
{
   // List histograms in the stack

   TROOT::IndentLevel();
   cout <<IsA()->GetName()
        <<" Name= "<<GetName()<<" Title= "<<GetTitle()<<" Option="<<option<<endl;
   TROOT::IncreaseDirLevel();
   if (fHists) fHists->ls(option);
   TROOT::DecreaseDirLevel();
}

//______________________________________________________________________________
void THStack::Modified()
{
// invalidate sum of histograms

   if (!fStack) return;
   fStack->Delete();
   delete fStack;
   fStack = 0;
}

//______________________________________________________________________________
void THStack::Paint(Option_t *option)
{
// paint the list of histograms
// By default, histograms are shown stacked.
//    -the first histogram is paint
//    -then the sum of the first and second, etc
// If option "nostack" is specified, histograms are all paint in the same pad
// as if the option "same" had been specified.
//
// See THistPainter::Paint for a list of valid options.

   TString opt = option;
   opt.ToLower();
   char loption[32];
   sprintf(loption,"%s",opt.Data());
   char *nostack = strstr(loption,"nostack");
   // do not delete the stack. Another pad may contain the same object
   // drawn in stack mode!
   //if (nostack && fStack) {fStack->Delete(); delete fStack; fStack = 0;}

   Double_t themax = GetMaximum(option);
   Double_t themin = GetMinimum(option);
   if (!fHistogram) {
      Bool_t add = TH1::AddDirectoryStatus();
      TH1::AddDirectory(kFALSE);
      TH1 *h = (TH1*)fHists->At(0);
      TAxis *xaxis = h->GetXaxis();
      TAxis *yaxis = h->GetYaxis();
      if (h->GetDimension() > 1) {
         if (strlen(option) == 0) strcpy(loption,"lego1");
         fHistogram = new TH2F(GetName(),GetTitle(),
                               xaxis->GetNbins(),xaxis->GetXmin(),xaxis->GetXmax(),
                               yaxis->GetNbins(),yaxis->GetXmin(),yaxis->GetXmax());
      } else {
         fHistogram = new TH1F(GetName(),GetTitle(),xaxis->GetNbins(),xaxis->GetXmin(),xaxis->GetXmax());
      }
      fHistogram->SetStats(0);
      TH1::AddDirectory(add);
   }

   if (nostack) {*nostack = 0; strcat(nostack,nostack+7);}
   else fHistogram->GetPainter()->SetStack(fHists);

   fHistogram->SetMaximum(1.05*themax);
   fHistogram->SetMinimum(themin);
   fHistogram->Paint(loption);

   if (fHistogram->GetDimension() > 1) SetDrawOption(loption);
   if (strstr(loption,"lego")) return;

   Int_t nhists = fHists->GetEntriesFast();
   strcat(loption,"same");
   for (Int_t i=0;i<nhists;i++) {
      if (nostack) fHists->At(i)->Paint(loption);
      else         fStack->At(nhists-i-1)->Paint(loption);
   }
}

//______________________________________________________________________________
void THStack::Print(Option_t *option) const
{
// Print the list of histograms

   TH1 *h;
   if (fHists) {
     TIter   next(fHists);
     while ((h = (TH1*) next())) {
       h->Print(option);
     }
   }
}

//______________________________________________________________________________
void THStack::SavePrimitive(ofstream &out, Option_t *option)
{
    // Save primitive as a C++ statement(s) on output stream out

   char quote = '"';
   out<<"   "<<endl;
   if (gROOT->ClassSaved(THStack::Class())) {
       out<<"   ";
   } else {
       out<<"   THStack *";
   }
   out<<"hstack = new THStack();"<<endl;
   out<<"   hstack->SetName("<<quote<<GetName()<<quote<<");"<<endl;
   out<<"   hstack->SetTitle("<<quote<<GetTitle()<<quote<<");"<<endl;

   TH1 *h;
   if (fHists) {
     TIter   next(fHists);
     while ((h = (TH1*) next())) {
       h->SavePrimitive(out,"nodraw");
       out<<"   hstack->Add("<<h->GetName()<<");"<<endl;
     }
   }
   out<<"   hstack->Draw("
      <<quote<<option<<quote<<");"<<endl;
}

//______________________________________________________________________________
void THStack::SetMaximum(Double_t maximum)
{
   fMaximum = maximum;
   if (fHistogram)  fHistogram->SetMaximum(maximum);
}

//______________________________________________________________________________
void THStack::SetMinimum(Double_t minimum)
{
   fMinimum = minimum;
   if (fHistogram) fHistogram->SetMinimum(minimum);
}
<commit_msg>added <iostream.h> to fix compilation with g++ v3.<commit_after>// Author: Rene Brun   12/10/2000

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#include "TROOT.h"
#include "THStack.h"
#include "TVirtualPad.h"
#include "TH2.h"

#include <fstream.h>
#include <iostream.h>

ClassImp(THStack)

//______________________________________________________________________________
//
//   A THStack is a collection of TH1 (or derived) objects
//   Use THStack::Add to add a new histogram to the list.
//   The THStack owns the objects in the list.
//   By default (if option "nostack" is not specified), histograms will be paint
//   stacked on top of each other.
//   Example;
//      THStack hs("hs","test stacked histograms");
//      TH1F *h1 = new TH1F("h1","test hstack",100,-4,4);
//      h1->FillRandom("gaus",20000);
//      h1->SetFillColor(kRed);
//      hs.Add(h1);
//      TH1F *h2 = new TH1F("h2","test hstack",100,-4,4);
//      h2->FillRandom("gaus",15000);
//      h2->SetFillColor(kBlue);
//      hs.Add(h2);
//      TH1F *h3 = new TH1F("h3","test hstack",100,-4,4);
//      h3->FillRandom("gaus",10000);
//      h3->SetFillColor(kGreen);
//      hs.Add(h3);
//      TCanvas c1("c1","stacked hists",10,10,700,900);
//      c1.Divide(1,2);
//      c1.cd(1);
//      hs.Draw();
//      c1.cd(2);
//      hs->Draw("nostack");
//
//  See a more complex example in $ROOTSYS/tutorials/hstack.C
//
//  Note that picking is supported for all drawing modes.

//______________________________________________________________________________
THStack::THStack(): TNamed()
{
// THStack default constructor

   fHists     = 0;
   fStack     = 0;
   fHistogram = 0;
   fMaximum   = -1111;
   fMinimum   = -1111;
}

//______________________________________________________________________________
THStack::THStack(const char *name, const char *title)
       : TNamed(name,title)
{
// constructor with name and title
   fHists     = 0;
   fStack     = 0;
   fHistogram = 0;
   fMaximum   = -1111;
   fMinimum   = -1111;
}

//______________________________________________________________________________
THStack::~THStack()
{
// THStack destructor

   if (!fHists) return;
   fHists->Delete();
   delete fHists;
   fHists = 0;
   if (fStack) {fStack->Delete(); delete fStack;}
   delete fHistogram;
   fHistogram = 0;
}

//______________________________________________________________________________
void THStack::Add(TH1 *h1)
{
   // add a new histogram to the list
   // Only 1-d histograms currently supported.
   // Note that all histograms in the list must have the same number
   // of channels and the same X axis.

   if (!h1) return;
   if (h1->GetDimension() > 2) {
      Error("Add","THStack supports only 1-d and 2-d histograms");
      return;
   }
   if (!fHists) fHists = new TObjArray();
   fHists->Add(h1);
}

//______________________________________________________________________________
void THStack::Browse(TBrowser *)
{
    Draw();
    gPad->Update();
}

//______________________________________________________________________________
void THStack::BuildStack()
{
//  build sum of all histograms
//  Build a separate list fStack containing the running sum of all histograms

   if (fStack) return;
   Int_t nhists = fHists->GetEntriesFast();
   fStack = new TObjArray(nhists);
   Bool_t add = TH1::AddDirectoryStatus();
   TH1::AddDirectory(kFALSE);
   TH1 *h = (TH1*)fHists->At(0)->Clone();
   fStack->Add(h);
   for (Int_t i=1;i<nhists;i++) {
      h = (TH1*)fHists->At(i)->Clone();
      h->Add((TH1*)fStack->At(i-1));
      fStack->AddAt(h,i);
   }
   TH1::AddDirectory(add);
}

//______________________________________________________________________________
Int_t THStack::DistancetoPrimitive(Int_t px, Int_t py)
{
// Compute distance from point px,py to each graph
//

//*-*- Are we on the axis?
   const Int_t kMaxDiff = 10;
   Int_t distance = 9999;
   if (fHistogram) {
      distance = fHistogram->DistancetoPrimitive(px,py);
      if (distance <= 0) {return distance;}
      if (distance <= 1) {gPad->SetSelected(fHistogram);return distance;}
   }

//*-*- Loop on the list of histograms
   if (!fHists) return distance;
   TH1 *h = 0;
   const char *doption = GetDrawOption();
   Int_t nhists = fHists->GetEntriesFast();
   for (Int_t i=0;i<nhists;i++) {
      h = (TH1*)fHists->At(i);
      if (fStack && !strstr(doption,"nostack")) h = (TH1*)fStack->At(i);
      Int_t dist = h->DistancetoPrimitive(px,py);
      if (dist < kMaxDiff) {
         gPad->SetSelected(fHists->At(i));
         gPad->SetCursor(kPointer);
         return dist;
      }
   }
   return distance;
}

//______________________________________________________________________________
void THStack::Draw(Option_t *option)
{
//*-*-*-*-*-*-*-*-*-*-*Draw this multihist with its current attributes*-*-*-*-*-*-*
//*-*                  ==========================================
//
//   Options to draw histograms  are described in THistPainter::Paint
// By default (if option "nostack" is not specified), histograms will be paint
// stacked on top of each other.

   TString opt = option;
   opt.ToLower();
   if (gPad) {
      if (!gPad->IsEditable()) (gROOT->GetMakeDefCanvas())();
      if (!opt.Contains("same")) {
         //the following statement is necessary in case one attempts to draw
         //a temporary histogram already in the current pad
         if (TestBit(kCanDelete)) gPad->GetListOfPrimitives()->Remove(this);
         gPad->Clear();
      }
   }
   AppendPad(opt.Data());
}

//______________________________________________________________________________
TH1 *THStack::GetHistogram() const
{
//    Returns a pointer to the histogram used to draw the axis
//    Takes into account the two following cases.
//       1- option 'A' was specified in THStack::Draw. Return fHistogram
//       2- user had called TPad::DrawFrame. return pointer to hframe histogram

   if (fHistogram) return fHistogram;
   if (!gPad) return 0;
   gPad->Modified();
   gPad->Update();
   if (fHistogram) return fHistogram;
   TH1 *h1 = (TH1*)gPad->FindObject("hframe");
   return h1;
}

//______________________________________________________________________________
Double_t THStack::GetMaximum(Option_t *option)
{
//  returns the maximum of all added histograms
//  returns the maximum of all histograms if option "nostack".

   TString opt = option;
   opt.ToLower();
   Double_t them=0, themax = -1e300;
   Int_t nhists = fHists->GetEntriesFast();
   TH1 *h;
   if (!opt.Contains("nostack")) {
       BuildStack();
       h = (TH1*)fStack->At(nhists-1);
       themax = h->GetMaximum();
   } else {
      for (Int_t i=0;i<nhists;i++) {
         h = (TH1*)fHists->At(i);
         them = h->GetMaximum();
         if (them > themax) themax = them;
      }
   }
   return themax;
}

//______________________________________________________________________________
Double_t THStack::GetMinimum(Option_t *option)
{
//  returns the minimum of all added histograms
//  returns the minimum of all histograms if option "nostack".

   TString opt = option;
   opt.ToLower();
   Double_t them=0, themin = 1e300;
   Int_t nhists = fHists->GetEntriesFast();
   TH1 *h;
   if (!opt.Contains("nostack")) {
       BuildStack();
       h = (TH1*)fStack->At(nhists-1);
       themin = h->GetMinimum();
   } else {
      for (Int_t i=0;i<nhists;i++) {
         h = (TH1*)fHists->At(i);
         them = h->GetMinimum();
         if (them < themin) themin = them;
      }
   }
   return themin;
}

//______________________________________________________________________________
TAxis *THStack::GetXaxis() const
{
   // Get x axis of the graph.

   if (!gPad) return 0;
   return GetHistogram()->GetXaxis();
}

//______________________________________________________________________________
TAxis *THStack::GetYaxis() const
{
   // Get y axis of the graph.

   if (!gPad) return 0;
   return GetHistogram()->GetYaxis();
}

//______________________________________________________________________________
void THStack::ls(Option_t *option) const
{
   // List histograms in the stack

   TROOT::IndentLevel();
   cout <<IsA()->GetName()
        <<" Name= "<<GetName()<<" Title= "<<GetTitle()<<" Option="<<option<<endl;
   TROOT::IncreaseDirLevel();
   if (fHists) fHists->ls(option);
   TROOT::DecreaseDirLevel();
}

//______________________________________________________________________________
void THStack::Modified()
{
// invalidate sum of histograms

   if (!fStack) return;
   fStack->Delete();
   delete fStack;
   fStack = 0;
}

//______________________________________________________________________________
void THStack::Paint(Option_t *option)
{
// paint the list of histograms
// By default, histograms are shown stacked.
//    -the first histogram is paint
//    -then the sum of the first and second, etc
// If option "nostack" is specified, histograms are all paint in the same pad
// as if the option "same" had been specified.
//
// See THistPainter::Paint for a list of valid options.

   TString opt = option;
   opt.ToLower();
   char loption[32];
   sprintf(loption,"%s",opt.Data());
   char *nostack = strstr(loption,"nostack");
   // do not delete the stack. Another pad may contain the same object
   // drawn in stack mode!
   //if (nostack && fStack) {fStack->Delete(); delete fStack; fStack = 0;}

   Double_t themax = GetMaximum(option);
   Double_t themin = GetMinimum(option);
   if (!fHistogram) {
      Bool_t add = TH1::AddDirectoryStatus();
      TH1::AddDirectory(kFALSE);
      TH1 *h = (TH1*)fHists->At(0);
      TAxis *xaxis = h->GetXaxis();
      TAxis *yaxis = h->GetYaxis();
      if (h->GetDimension() > 1) {
         if (strlen(option) == 0) strcpy(loption,"lego1");
         fHistogram = new TH2F(GetName(),GetTitle(),
                               xaxis->GetNbins(),xaxis->GetXmin(),xaxis->GetXmax(),
                               yaxis->GetNbins(),yaxis->GetXmin(),yaxis->GetXmax());
      } else {
         fHistogram = new TH1F(GetName(),GetTitle(),xaxis->GetNbins(),xaxis->GetXmin(),xaxis->GetXmax());
      }
      fHistogram->SetStats(0);
      TH1::AddDirectory(add);
   }

   if (nostack) {*nostack = 0; strcat(nostack,nostack+7);}
   else fHistogram->GetPainter()->SetStack(fHists);

   fHistogram->SetMaximum(1.05*themax);
   fHistogram->SetMinimum(themin);
   fHistogram->Paint(loption);

   if (fHistogram->GetDimension() > 1) SetDrawOption(loption);
   if (strstr(loption,"lego")) return;

   Int_t nhists = fHists->GetEntriesFast();
   strcat(loption,"same");
   for (Int_t i=0;i<nhists;i++) {
      if (nostack) fHists->At(i)->Paint(loption);
      else         fStack->At(nhists-i-1)->Paint(loption);
   }
}

//______________________________________________________________________________
void THStack::Print(Option_t *option) const
{
// Print the list of histograms

   TH1 *h;
   if (fHists) {
     TIter   next(fHists);
     while ((h = (TH1*) next())) {
       h->Print(option);
     }
   }
}

//______________________________________________________________________________
void THStack::SavePrimitive(ofstream &out, Option_t *option)
{
    // Save primitive as a C++ statement(s) on output stream out

   char quote = '"';
   out<<"   "<<endl;
   if (gROOT->ClassSaved(THStack::Class())) {
       out<<"   ";
   } else {
       out<<"   THStack *";
   }
   out<<"hstack = new THStack();"<<endl;
   out<<"   hstack->SetName("<<quote<<GetName()<<quote<<");"<<endl;
   out<<"   hstack->SetTitle("<<quote<<GetTitle()<<quote<<");"<<endl;

   TH1 *h;
   if (fHists) {
     TIter   next(fHists);
     while ((h = (TH1*) next())) {
       h->SavePrimitive(out,"nodraw");
       out<<"   hstack->Add("<<h->GetName()<<");"<<endl;
     }
   }
   out<<"   hstack->Draw("
      <<quote<<option<<quote<<");"<<endl;
}

//______________________________________________________________________________
void THStack::SetMaximum(Double_t maximum)
{
   fMaximum = maximum;
   if (fHistogram)  fHistogram->SetMaximum(maximum);
}

//______________________________________________________________________________
void THStack::SetMinimum(Double_t minimum)
{
   fMinimum = minimum;
   if (fHistogram) fHistogram->SetMinimum(minimum);
}
<|endoftext|>


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

#pragma once

#include "libgearman/magic.h"

struct gearman_universal_st;

/**
 * @ingroup gearman_packet
 */
struct gearman_packet_st
{
  struct Options {
    const bool is_allocated;
    bool complete;
    bool free_data;

    Options(bool is_allocted_) :
      is_allocated(is_allocted_),
      complete(false),
      free_data(false)
    { }
  } options;
  enum gearman_magic_t magic;
  gearman_command_t command;
  uint8_t argc;
  size_t args_size;
  size_t data_size;
  gearman_universal_st *universal;
  gearman_packet_st *next;
  gearman_packet_st *prev;
  char *args;
  const void *data;
  char *arg[GEARMAN_MAX_COMMAND_ARGS];
  size_t arg_size[GEARMAN_MAX_COMMAND_ARGS];
  char args_buffer[GEARMAN_ARGS_BUFFER_SIZE];
#ifdef GEARMAN_PACKET_TRACE
  uint32_t _id;
#endif

  gearman_packet_st(bool is_allocted_= false) :
    options(is_allocted_),
    magic(GEARMAN_MAGIC_TEXT),
    command(GEARMAN_COMMAND_TEXT),
    argc(0),
    args_size(0),
    data_size(0),
    universal(0),
    next(0),
    prev(0),
    args(0),
    data(0)
  {
  }

  ~gearman_packet_st()
  {
    reset();
  }

  void free__data();

  bool failed() const
  {
    if (command == GEARMAN_COMMAND_WORK_FAIL)
    {
      return true;
    }

    return false;
  }

  size_t size() const
  {
    return data_size;
  }

  const char* value(size_t& length_) const
  {
    length_= data_size;

    if (length_)
    {
      return (const char*)data;
    }

    return NULL;
  }

  const char* value() const
  {
    if (data_size)
    {
      return (const char*)data;
    }

    return NULL;
  }

  void reset();
};
<commit_msg>gearman_packet_st refactoring<commit_after>/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
 *
 *  Gearmand client and server library.
 *
 *  Copyright (C) 2011-2013 Data Differential, http://datadifferential.com/
 *  Copyright (C) 2008 Brian Aker, Eric Day
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are
 *  met:
 *
 *      * Redistributions of source code must retain the above copyright
 *  notice, this list of conditions and the following disclaimer.
 *
 *      * Redistributions in binary form must reproduce the above
 *  copyright notice, this list of conditions and the following disclaimer
 *  in the documentation and/or other materials provided with the
 *  distribution.
 *
 *      * The names of its contributors may not be used to endorse or
 *  promote products derived from this software without specific prior
 *  written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

#pragma once

#include "libgearman/magic.h"

struct gearman_universal_st;

/**
 * @ingroup gearman_packet
 */
struct gearman_packet_st
{
  struct Options {
    const bool is_allocated;
    bool complete;
    bool free_data;

    Options(bool is_allocted_) :
      is_allocated{is_allocted_},
      complete{false},
      free_data{false}
    { }
  } options;
  enum gearman_magic_t magic;
  gearman_command_t command;
  uint8_t argc;
  size_t args_size;
  size_t data_size;
  gearman_universal_st *universal;
  gearman_packet_st *next;
  gearman_packet_st *prev;
  char *args;
  const void *data;
  char *arg[GEARMAN_MAX_COMMAND_ARGS];
  size_t arg_size[GEARMAN_MAX_COMMAND_ARGS];
  char args_buffer[GEARMAN_ARGS_BUFFER_SIZE];
#ifdef GEARMAN_PACKET_TRACE
  uint32_t _id;
#endif

  gearman_packet_st(bool is_allocted_= false) :
    options{is_allocted_},
    magic{GEARMAN_MAGIC_TEXT},
    command{GEARMAN_COMMAND_TEXT},
    argc{0},
    args_size{0},
    data_size{0},
    universal{0},
    next{nullptr},
    prev{nullptr},
    args{nullptr},
    data{nullptr}
  {
  }

  ~gearman_packet_st()
  {
    reset();
  }

  void free__data();

  bool failed() const
  {
    if (command == GEARMAN_COMMAND_WORK_FAIL)
    {
      return true;
    }

    return false;
  }

  size_t size() const
  {
    return data_size;
  }

  const char* value(size_t& length_) const
  {
    length_= data_size;

    if (length_)
    {
      return (const char*)data;
    }

    return nullptr;
  }

  const char* value() const
  {
    if (data_size)
    {
      return (const char*)data;
    }

    return nullptr;
  }

  void reset();
};
<|endoftext|>


<commit_before>/*
    kopetecontactlist.cpp - Kopete's Contact List backend

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

    Copyright (c) 2002 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 "kopetecontactlist.h"

#include "kopete.h"
#include "kopetecontactlistview.h"
#include "kopetemetacontact.h"
#include "kopetemetacontactlvi.h"
#include "kopeteprotocol.h"
#include "pluginloader.h"

#include <qptrlist.h>
#include <qstringlist.h>
#include <qstylesheet.h>

#include <klocale.h>
#include <kapplication.h>
#include <kdebug.h>
#include <kglobal.h>
#include <kstandarddirs.h>

KopeteContactList *KopeteContactList::s_contactList = 0L;

KopeteContactList *KopeteContactList::contactList()
{
	if( !s_contactList )
		s_contactList = new KopeteContactList;

	return s_contactList;
}

KopeteContactList::KopeteContactList()
: QObject( kapp, "KopeteContactList" )
{
}

KopeteContactList::~KopeteContactList()
{
}

KopeteMetaContact *KopeteContactList::findContact( const QString &protocolId,
	const QString &identityId, const QString &contactId )
{
	//kdDebug() << "*** Looking for contact " << contactId << ", proto "
	//	<< protocolId << endl;
	QPtrListIterator<KopeteMetaContact> it( m_contacts );
	for( ; it.current(); ++it )
	{
		//kdDebug() << "*** Iterating " << it.current()->displayName() << endl;
		KopeteContact *c = it.current()->findContact( protocolId, identityId,
			contactId );
		if( c )
			return it.current();
	}
	//kdDebug() << "*** Not found!" << endl;

	// Contact not found, create a new meta contact
	KopeteMetaContact *mc = new KopeteMetaContact();
	//m_contacts.append( c );
	KopeteContactList::contactList()->addMetaContact(mc);

	return mc;
}

void KopeteContactList::addMetaContact( KopeteMetaContact *mc )
{
	QStringList groups;

	groups = mc->groups();

	m_contacts.append( mc );

	connect( mc, SIGNAL( addedToGroup( KopeteMetaContact *, const QString & ) ),
		this, SLOT(slotAddedToGroup( KopeteMetaContact *, const QString & ) ) );
    connect( mc, SIGNAL( removedFromGroup( KopeteMetaContact *, const QString & ) ),
		this, SLOT(slotRemovedFromGroup( KopeteMetaContact *, const QString & ) ) );

	if ( groups.isEmpty() )
	{
		kdDebug() << "KopeteContactList::addMetaContact : adding metacontact with no groups" <<endl;
		kopeteapp->contactList()->addContact(new KopeteMetaContactLVI( mc, kopeteapp->contactList() ) );
	}
	else
	{
		QStringList::ConstIterator it = groups.begin();
		for( ; it != groups.end(); ++it )
		{
			QString group = *it;
			kdDebug() << "KopeteContactList::addMetaContact: "
				<< "adding metacontact to group " << group <<endl;
			kopeteapp->contactList()->addContact( new KopeteMetaContactLVI(
				mc, kopeteapp->contactList()->getGroup( group ) ) );
		}
	}
}

void KopeteContactList::slotAddedToGroup( KopeteMetaContact *mc, const QString &to )
{
	kopeteapp->contactList()->addContact( new KopeteMetaContactLVI(
				mc, kopeteapp->contactList()->getGroup( to ) ) );
}

void KopeteContactList::slotRemovedFromGroup(KopeteMetaContact *mc, const QString &from )
{
	kopeteapp->contactList()->removeContact( mc, from );
}

void KopeteContactList::loadXML()
{
	QDomDocument contactList( "messaging-contact-list" );

	QString filename = locateLocal( "appdata", "contactlist.xml" );

	if( filename.isEmpty() )
		return ;

	QFile contactListFile( filename );
	contactListFile.open( IO_ReadOnly );
	contactList.setContent( &contactListFile );

	QDomElement list = contactList.documentElement();
	QDomNode node = list.firstChild();
	while( !node.isNull() )
	{
		QDomElement element = node.toElement();
		if( !element.isNull() )
		{
			if( element.tagName() == "meta-contact" )
			{
				//TODO: id isn't used
				QString id = element.attribute( "id", QString::null );
				KopeteMetaContact *metaContact = new KopeteMetaContact();

				QDomNode contactNode = node.firstChild();
				if ( !metaContact->fromXML( contactNode ) )
				{
					delete metaContact;
					metaContact = 0;
				}
				else
				{
					KopeteContactList::contactList()->addMetaContact(
						metaContact );
				}
			}
			else
			{
				kdDebug() << "KopeteContactList::loadXML: Warning: "
					  << "Unknown element '" << element.tagName()
					  << "' in contact list!" << endl;
			}

		}
		node = node.nextSibling();
	}
	contactListFile.close();
}

void KopeteContactList::saveXML()
{
	QString contactListFileName = locateLocal( "appdata", "contactlist.xml" );

	//kdDebug() << "KopeteContactList::saveXML: Contact List File: "
	//	<< contactListFileName << endl;
	QFile contactListFile( contactListFileName );
	if( contactListFile.open( IO_WriteOnly ) )
	{
		QTextStream stream( &contactListFile );
		stream.setEncoding( QTextStream::UnicodeUTF8 );

		stream << toXML();

		contactListFile.close();
	}
	else
	{
		kdDebug() << "WARNING: Couldn't open contact list file "
			<< contactListFileName << ". Contact list not saved." << endl;
	}
}

QString KopeteContactList::toXML()
{
	QString xml = "<?xml version=\"1.0\"?>\n"
		"<messaging-contact-list>\n";

	QPtrListIterator<KopeteMetaContact> metaContactIt( m_contacts );
	for( ; metaContactIt.current(); ++metaContactIt )
	{
		kdDebug() << "KopeteContactList::toXML: Saving meta contact "
			<< ( *metaContactIt )->displayName() << endl;
		xml +=  ( *metaContactIt)->toXML();
	}

	xml += "</messaging-contact-list>\n";

	return xml;
}

QStringList KopeteContactList::contacts() const
{
	QStringList contacts;
	QPtrListIterator<KopeteMetaContact> it( m_contacts );
	for( ; it.current(); ++it )
	{
		contacts.append( it.current()->displayName() );
	}
	return contacts;
}

QStringList KopeteContactList::contactStatuses() const
{
	QStringList meta_contacts;
	QPtrListIterator<KopeteMetaContact> it( m_contacts );
	for( ; it.current(); ++it )
	{
		meta_contacts.append( QString( "%1 (%2)" ).arg(
			it.current()->displayName() ).arg(
			it.current()->statusString() ) );
	}
	return meta_contacts;
}

QStringList KopeteContactList::reachableContacts() const
{
	QStringList contacts;
	QPtrListIterator<KopeteMetaContact> it( m_contacts );
	for( ; it.current(); ++it )
	{
		if ( it.current()->isReachable() )
			contacts.append( it.current()->displayName() );
	}
	return contacts;
}

QStringList KopeteContactList::onlineContacts() const
{
	QStringList contacts;
	QPtrListIterator<KopeteMetaContact> it( m_contacts );
	for( ; it.current(); ++it )
	{
		if ( it.current()->isOnline() )
			contacts.append( it.current()->displayName() );
	}
	return contacts;
}

QStringList KopeteContactList::groups() const
{
	QStringList groups;

	QPtrListIterator<KopeteMetaContact> it( m_contacts );
	kdDebug() << "[AddContactWizard] ****************************" <<endl;

	for( ; it.current(); ++it )
	{
		QStringList thisgroups;

		/* We get groups for this metacontact */
		thisgroups = it.current()->groups();

		if ( thisgroups.isEmpty() ) continue;

		for( QStringList::ConstIterator it = thisgroups.begin();
			it != thisgroups.end(); ++it )
		{
			 /* We add the group only if it is not already there */
			QString groupname = (*it);
			if ( ! groups.contains( groupname ) && !groupname.isNull() )
			{
				kdDebug() << "[AddContactWizard] Adding group ["
					<< groupname << "]" <<endl;
				groups.append( *it );
			}
		}
	}
	kdDebug() << "[AddContactWizard] ****************************" <<endl;

	return groups;
}

#include "kopetecontactlist.moc"

// vim: set noet ts=4 sts=4 sw=4:

<commit_msg>Fixes adding a toplevel contact to a group<commit_after>/*
    kopetecontactlist.cpp - Kopete's Contact List backend

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

    Copyright (c) 2002 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 "kopetecontactlist.h"

#include "kopete.h"
#include "kopetecontactlistview.h"
#include "kopetemetacontact.h"
#include "kopetemetacontactlvi.h"
#include "kopeteprotocol.h"
#include "pluginloader.h"

#include <qptrlist.h>
#include <qstringlist.h>
#include <qstylesheet.h>

#include <klocale.h>
#include <kapplication.h>
#include <kdebug.h>
#include <kglobal.h>
#include <kstandarddirs.h>

KopeteContactList *KopeteContactList::s_contactList = 0L;

KopeteContactList *KopeteContactList::contactList()
{
	if( !s_contactList )
		s_contactList = new KopeteContactList;

	return s_contactList;
}

KopeteContactList::KopeteContactList()
: QObject( kapp, "KopeteContactList" )
{
}

KopeteContactList::~KopeteContactList()
{
}

KopeteMetaContact *KopeteContactList::findContact( const QString &protocolId,
	const QString &identityId, const QString &contactId )
{
	//kdDebug() << "*** Looking for contact " << contactId << ", proto "
	//	<< protocolId << endl;
	QPtrListIterator<KopeteMetaContact> it( m_contacts );
	for( ; it.current(); ++it )
	{
		//kdDebug() << "*** Iterating " << it.current()->displayName() << endl;
		KopeteContact *c = it.current()->findContact( protocolId, identityId,
			contactId );
		if( c )
			return it.current();
	}
	//kdDebug() << "*** Not found!" << endl;

	// Contact not found, create a new meta contact
	KopeteMetaContact *mc = new KopeteMetaContact();
	//m_contacts.append( c );
	KopeteContactList::contactList()->addMetaContact(mc);

	return mc;
}

void KopeteContactList::addMetaContact( KopeteMetaContact *mc )
{
	QStringList groups;

	groups = mc->groups();

	m_contacts.append( mc );

	connect( mc, SIGNAL( addedToGroup( KopeteMetaContact *, const QString & ) ),
		this, SLOT(slotAddedToGroup( KopeteMetaContact *, const QString & ) ) );
    connect( mc, SIGNAL( removedFromGroup( KopeteMetaContact *, const QString & ) ),
		this, SLOT(slotRemovedFromGroup( KopeteMetaContact *, const QString & ) ) );

	if ( groups.isEmpty() )
	{
		kdDebug() << "KopeteContactList::addMetaContact : adding metacontact with no groups" <<endl;
		kopeteapp->contactList()->addContact( mc );
	}
	else
	{
		QStringList::ConstIterator it = groups.begin();
		for( ; it != groups.end(); ++it )
		{
			QString group = *it;
			kdDebug() << "KopeteContactList::addMetaContact: "
				<< "adding metacontact to group " << group <<endl;
			kopeteapp->contactList()->addContact( mc, group );
		}
	}
}

void KopeteContactList::slotAddedToGroup( KopeteMetaContact *mc, const QString &to )
{
	kopeteapp->contactList()->addContact( mc, to );

	if ( (mc->groups()).count() == 1 )
	{
		kopeteapp->contactList()->removeTopLevel(mc);
	}
}

void KopeteContactList::slotRemovedFromGroup(KopeteMetaContact *mc, const QString &from )
{
	kopeteapp->contactList()->removeContact( mc, from );

	if ( (mc->groups()).isEmpty() )
	{
		kopeteapp->contactList()->addContact(mc);
	}

}

void KopeteContactList::loadXML()
{
	QDomDocument contactList( "messaging-contact-list" );

	QString filename = locateLocal( "appdata", "contactlist.xml" );

	if( filename.isEmpty() )
		return ;

	QFile contactListFile( filename );
	contactListFile.open( IO_ReadOnly );
	contactList.setContent( &contactListFile );

	QDomElement list = contactList.documentElement();
	QDomNode node = list.firstChild();
	while( !node.isNull() )
	{
		QDomElement element = node.toElement();
		if( !element.isNull() )
		{
			if( element.tagName() == "meta-contact" )
			{
				//TODO: id isn't used
				QString id = element.attribute( "id", QString::null );
				KopeteMetaContact *metaContact = new KopeteMetaContact();

				QDomNode contactNode = node.firstChild();
				if ( !metaContact->fromXML( contactNode ) )
				{
					delete metaContact;
					metaContact = 0;
				}
				else
				{
					KopeteContactList::contactList()->addMetaContact(
						metaContact );
				}
			}
			else
			{
				kdDebug() << "KopeteContactList::loadXML: Warning: "
					  << "Unknown element '" << element.tagName()
					  << "' in contact list!" << endl;
			}

		}
		node = node.nextSibling();
	}
	contactListFile.close();
}

void KopeteContactList::saveXML()
{
	QString contactListFileName = locateLocal( "appdata", "contactlist.xml" );

	//kdDebug() << "KopeteContactList::saveXML: Contact List File: "
	//	<< contactListFileName << endl;
	QFile contactListFile( contactListFileName );
	if( contactListFile.open( IO_WriteOnly ) )
	{
		QTextStream stream( &contactListFile );
		stream.setEncoding( QTextStream::UnicodeUTF8 );

		stream << toXML();

		contactListFile.close();
	}
	else
	{
		kdDebug() << "WARNING: Couldn't open contact list file "
			<< contactListFileName << ". Contact list not saved." << endl;
	}
}

QString KopeteContactList::toXML()
{
	QString xml = "<?xml version=\"1.0\"?>\n"
		"<messaging-contact-list>\n";

	QPtrListIterator<KopeteMetaContact> metaContactIt( m_contacts );
	for( ; metaContactIt.current(); ++metaContactIt )
	{
		kdDebug() << "KopeteContactList::toXML: Saving meta contact "
			<< ( *metaContactIt )->displayName() << endl;
		xml +=  ( *metaContactIt)->toXML();
	}

	xml += "</messaging-contact-list>\n";

	return xml;
}

QStringList KopeteContactList::contacts() const
{
	QStringList contacts;
	QPtrListIterator<KopeteMetaContact> it( m_contacts );
	for( ; it.current(); ++it )
	{
		contacts.append( it.current()->displayName() );
	}
	return contacts;
}

QStringList KopeteContactList::contactStatuses() const
{
	QStringList meta_contacts;
	QPtrListIterator<KopeteMetaContact> it( m_contacts );
	for( ; it.current(); ++it )
	{
		meta_contacts.append( QString( "%1 (%2)" ).arg(
			it.current()->displayName() ).arg(
			it.current()->statusString() ) );
	}
	return meta_contacts;
}

QStringList KopeteContactList::reachableContacts() const
{
	QStringList contacts;
	QPtrListIterator<KopeteMetaContact> it( m_contacts );
	for( ; it.current(); ++it )
	{
		if ( it.current()->isReachable() )
			contacts.append( it.current()->displayName() );
	}
	return contacts;
}

QStringList KopeteContactList::onlineContacts() const
{
	QStringList contacts;
	QPtrListIterator<KopeteMetaContact> it( m_contacts );
	for( ; it.current(); ++it )
	{
		if ( it.current()->isOnline() )
			contacts.append( it.current()->displayName() );
	}
	return contacts;
}

QStringList KopeteContactList::groups() const
{
	QStringList groups;

	QPtrListIterator<KopeteMetaContact> it( m_contacts );
	kdDebug() << "[AddContactWizard] ****************************" <<endl;

	for( ; it.current(); ++it )
	{
		QStringList thisgroups;

		/* We get groups for this metacontact */
		thisgroups = it.current()->groups();

		if ( thisgroups.isEmpty() ) continue;

		for( QStringList::ConstIterator it = thisgroups.begin();
			it != thisgroups.end(); ++it )
		{
			 /* We add the group only if it is not already there */
			QString groupname = (*it);
			if ( ! groups.contains( groupname ) && !groupname.isNull() )
			{
				kdDebug() << "[AddContactWizard] Adding group ["
					<< groupname << "]" <<endl;
				groups.append( *it );
			}
		}
	}
	kdDebug() << "[AddContactWizard] ****************************" <<endl;

	return groups;
}

#include "kopetecontactlist.moc"

// vim: set noet ts=4 sts=4 sw=4:

<|endoftext|>


<commit_before>/*
    kopetexsl.cpp - Kopete XSL Routines

    Copyright (c) 2003      by Jason Keirstead       <jason@keirstead.org>
    Copyright (c) 2003      by Martijn Klingens      <klingens@kde.org>

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

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

#include "kopetexsl.h"

#include <libxml/globals.h>
#include <libxml/parser.h>
#include <libxslt/transform.h>
#include <libxslt/xsltInternals.h>
#include <libxslt/xsltconfig.h>

// Solaris Fix
// FIXME: _why_ is including stdlib.h a Solaris fix? Stuff like this should
//        be documented - Martijn
#include <stdlib.h>

#include <qregexp.h>
#include <qsignal.h>
#include <qthread.h>

#include <kdebug.h>
#include <klocale.h>

/**
 * @author Jason Keirstead <jason@keirstead.org>
 *
 * The thread class that actually performs the XSL processing.
 * Using a thread allows async operation.
 */
class KopeteXSLThread : public QThread
{
public:
	/**
	 * Thread constructor
	 *
	 * @param xmlString The XML to be transformed
	 * @param xslString The XSL string we will use to transform
	 * @param target Target object to connect to for async operation
	 * @param slotCompleted Slot to fire on completion in asnc operation
	 */
	KopeteXSLThread( const QString &xmlString, const QCString &xslString, QObject *target = 0L, const char *slotCompleted = 0L );

	/**
	 * Reimplemented from QThread. Does the processing.
	 */
	virtual void run();

	static QString xsltTransform( const QString &xmlString, const QCString &xsltString );

	/**
	 * Returns the result string
	 */
	const QString &result()
	{ return m_resultString; };

private:
	QString m_xml;
	QCString m_xsl;
	QString m_resultString;
	QObject *m_target;
	const char *m_slotCompleted;
};

KopeteXSLThread::KopeteXSLThread( const QString &xmlString, const QCString &xsltString, QObject *target, const char *slotCompleted )
{
	m_xml = xmlString;
	m_xsl = xsltString;

	m_target = target;
	m_slotCompleted = slotCompleted;
}

void KopeteXSLThread::run()
{
	m_resultString = xsltTransform( m_xml, m_xsl );

	// Signal completion
	if( m_target && m_slotCompleted )
	{
		QSignal completeSignal( m_target );
		completeSignal.connect( m_target, m_slotCompleted );
		completeSignal.setValue( m_resultString );
		completeSignal.activate();

		// FIXME: Why no 'delete this' if there's no slotCompleted? - Martijn
		delete this;
	}
}

QString KopeteXSLThread::xsltTransform( const QString &xmlString, const QCString &xslCString )
{
	// Init Stuff
	xmlLoadExtDtdDefaultValue = 0;
	xmlSubstituteEntitiesDefault( 1 );

	// Convert QString into a C string
	QCString xmlCString = xmlString.utf8();

	QString resultString;
	QString errorMsg;

	// Read XML docs in from memory
	xmlDocPtr xmlDoc = xmlParseMemory( xmlCString, xmlCString.length() );
	if ( xmlDoc )
	{
		xmlDocPtr xslDoc = xmlParseMemory( xslCString, xslCString.length() );
		if ( xslDoc )
		{
			xsltStylesheetPtr styleSheet = xsltParseStylesheetDoc( xslDoc );
			if ( styleSheet )
			{
				xmlDocPtr resultDoc = xsltApplyStylesheet( styleSheet, xmlDoc, NULL );
				if ( resultDoc )
				{
					// Save the result into the QString
					xmlChar *mem;
					int size;
					xmlDocDumpMemory( resultDoc, &mem, &size );
					resultString = QString::fromUtf8( QCString( ( char * )( mem ), size + 1 ) );
					free( mem );
					xmlFreeDoc( resultDoc );
				}
				else
				{
					errorMsg = i18n( "Transformed document is null!" );
				}
				xsltFreeStylesheet( styleSheet );

				// FIXME: No xmlFreeDoc( xslDoc ) here? - Martijn
			}
			else
			{
				errorMsg = i18n( "Document is not valid XSL!" );
				xmlFreeDoc( xslDoc );
			}
		}
		else
		{
			errorMsg = i18n( "XSL document could not be parsed!" );
		}
		xmlFreeDoc( xmlDoc );
	}
	else
	{
		errorMsg = i18n( "XML document could not be parsed!" );
	}

	if ( resultString.isEmpty() )
		resultString = i18n( "
An internal Kopete error occurred while parsing a message:
%1
" ).arg( errorMsg );

	return resultString;
}

class KopeteXSLTPrivate
{
public:
	QCString document;
};

KopeteXSLT::KopeteXSLT( const QString &document, QObject *parent )
: QObject( parent )
{
	d = new KopeteXSLTPrivate;

	setXSLT( document );
}

KopeteXSLT::~KopeteXSLT()
{
	delete d;
}

void KopeteXSLT::setXSLT( const QString &_document )
{
	// Search for '<kopete-i18n>' elements and feed them through i18n().
	// After that replace the %VAR% variables with their proper XSLT counterpart.
	//
	// FIXME: Preprocessing the document using the QString API is fast and simple,
	//        but also error-sensitive.
	//        In fact, there are a couple of known issues with this algorithm that
	//        depend on the strings in the current styles. If these strings change
	//        they may break the parsing here.
	//
	//        The reason I'm doing it like this is because of issues with QDOM and
	//        namespaces in earlier Qt versions. When we drop Qt 3.1.x support we
	//        should probably convert this to more accurate DOM code. - Martijn
	QRegExp elementMatch( QString::fromLatin1( "<kopete-i18n>(.*)</kopete-i18n>" ) );
	elementMatch.setMinimal( true );
	QString document = _document;
	int pos;
	while ( ( pos = elementMatch.search( document ) ) != -1 )
	{
		QString orig = elementMatch.cap( 1 );
		//kdDebug( 14010 ) << k_funcinfo << "Original text: " << orig << endl;

		// Split on % and go over all parts
		QStringList parts = QStringList::split( '%', i18n( orig.utf8() ), true );

		// The first part is always text, as our variables are written like %FOO%
		QStringList::Iterator it = parts.begin();
		QString trans = *it;
		bool prependPercent = true;
		it = parts.remove( it );
		for ( it = parts.begin(); it != parts.end(); ++it )
		{
			prependPercent = false;
			if ( *it == QString::fromLatin1( "TIME" ) )
			{
				trans += QString::fromLatin1( "<xsl:value-of select=\"@time\"/>" );
			}
			else if ( *it == QString::fromLatin1( "FROM_CONTACT_DISPLAYNAME" ) )
			{
				trans += QString::fromLatin1( "<xsl:attribute name=\"title\">"
					"<xsl:choose>"
						"<xsl:when test='from/contact/@contactId=from/contact/@metaContactDisplayName'>"
							"<xsl:value-of disable-output-escaping=\"yes\" select=\"from/contact/@contactId\"/>"
						"</xsl:when>"
						"<xsl:otherwise>"
							"<xsl:value-of disable-output-escaping=\"yes\" select=\"from/contact/@contactId\"/>"
							" <xsl:value-of disable-output-escaping=\"yes\" select=\"from/contact/@metaContactDisplayName\"/>"
						"</xsl:otherwise>"
					"</xsl:choose></xsl:attribute>"
					"<xsl:value-of disable-output-escaping=\"yes\" select=\"from/contact/@contactDisplayName\"/>" );
			}
			else if ( *it == QString::fromLatin1( "TO_CONTACT_DISPLAYNAME" ) )
			{
				trans += QString::fromLatin1( "<xsl:attribute name=\"title\">"
					"<xsl:choose>"
						"<xsl:when test='to/contact/@contactId=to/contact/@metaContactDisplayName'>"
							"<xsl:value-of disable-output-escaping=\"yes\" select=\"to/contact/@contactId\"/>"
						"</xsl:when>"
						"<xsl:otherwise>"
							"<xsl:value-of disable-output-escaping=\"yes\" select=\"to/contact/@contactId\"/>"
							" <xsl:value-of disable-output-escaping=\"yes\" select=\"to/contact/@metaContactDisplayName\"/>"
						"</xsl:otherwise>"
					"</xsl:choose></xsl:attribute>"
					"<xsl:value-of disable-output-escaping=\"yes\" select=\"to/contact/@contactDisplayName\"/>" );
			}
			else if ( *it == QString::fromLatin1( "FROM_METACONTACT_DISPLAYNAME" ) )
			{
				trans += QString::fromLatin1( "<xsl:value-of disable-output-escaping=\"yes\" select=\"from/contact/@metaContactDisplayName\"/>" );
			}
			else if ( *it == QString::fromLatin1( "TO_METACONTACT_DISPLAYNAME" ) )
			{
				trans += QString::fromLatin1( "<xsl:value-of disable-output-escaping=\"yes\" select=\"to/contact/@metaContactDisplayName\"/>" );
			}
			else if ( *it == QString::fromLatin1( "FROM_CONTACT_ID" ) )
			{
				trans += QString::fromLatin1( "<xsl:attribute name=\"title\">"
					"<xsl:value-of disable-output-escaping=\"yes\" select=\"from/contact/@contactDisplayName\"/></xsl:attribute>"
					"<xsl:value-of disable-output-escaping=\"yes\" select=\"from/contact/@contactId\"/>" );
			}
			else if ( *it == QString::fromLatin1( "TO_CONTACT_ID" ) )
			{
				trans += QString::fromLatin1( "<xsl:attribute name=\"title\">"
					"<xsl:value-of disable-output-escaping=\"yes\" select=\"to/contact/@contactDisplayName\"/></xsl:attribute>"
					"<xsl:value-of disable-output-escaping=\"yes\" select=\"to/contact/@contactId\"/>" );
			}
			else if ( *it == QString::fromLatin1( "BODY" ) )
			{
				trans += QString::fromLatin1( "<xsl:value-of disable-output-escaping=\"yes\" select=\"body\"/>" );
			}
			else
			{
				if ( prependPercent )
					trans += '%';
				trans += *it;
				prependPercent = true;
			}
		}
		//kdDebug( 14010 ) << k_funcinfo << "Translated text: " << trans << endl;
		// Add "<kopete-i18n>" and "</kopete-i18n>" to length, hence the '+ 27'
		document.replace( uint( pos ), orig.length() + 27, trans );
	}
	d->document = document.utf8();
}

QString KopeteXSLT::transform( const QString &xmlString )
{
	return KopeteXSLThread::xsltTransform( xmlString, d->document );
}

void KopeteXSLT::transformAsync( const QString &xmlString, QObject *target, const char *slotCompleted )
{
	( new KopeteXSLThread( xmlString, d->document, target, slotCompleted ) )->start();
}

bool KopeteXSLT::isValid()
{
	bool retVal = false;

	// Init Stuff
	xmlLoadExtDtdDefaultValue = 0;
	xmlSubstituteEntitiesDefault( 1 );

	xmlDocPtr xslDoc = xmlParseMemory( d->document, d->document.length() );
	if ( xslDoc )
	{
		xsltStylesheetPtr styleSheet = xsltParseStylesheetDoc( xslDoc );
		if ( styleSheet )
		{
			retVal = true;
			xsltFreeStylesheet( styleSheet );
		}
		else
		{
			xmlFreeDoc( xslDoc );
		}
	}

	return retVal;
}

#include "kopetexsl.moc"

// vim: set noet ts=4 sts=4 sw=4:

<commit_msg>libxslt compile fix<commit_after>/*
    kopetexsl.cpp - Kopete XSL Routines

    Copyright (c) 2003      by Jason Keirstead       <jason@keirstead.org>
    Copyright (c) 2003      by Martijn Klingens      <klingens@kde.org>

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

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

#include "kopetexsl.h"

#include <libxml/globals.h>
#include <libxml/parser.h>
#include <libxslt/xsltInternals.h>
#include <libxslt/transform.h>
#include <libxslt/xsltconfig.h>

// Solaris Fix
// FIXME: _why_ is including stdlib.h a Solaris fix? Stuff like this should
//        be documented - Martijn
#include <stdlib.h>

#include <qregexp.h>
#include <qsignal.h>
#include <qthread.h>

#include <kdebug.h>
#include <klocale.h>

/**
 * @author Jason Keirstead <jason@keirstead.org>
 *
 * The thread class that actually performs the XSL processing.
 * Using a thread allows async operation.
 */
class KopeteXSLThread : public QThread
{
public:
	/**
	 * Thread constructor
	 *
	 * @param xmlString The XML to be transformed
	 * @param xslString The XSL string we will use to transform
	 * @param target Target object to connect to for async operation
	 * @param slotCompleted Slot to fire on completion in asnc operation
	 */
	KopeteXSLThread( const QString &xmlString, const QCString &xslString, QObject *target = 0L, const char *slotCompleted = 0L );

	/**
	 * Reimplemented from QThread. Does the processing.
	 */
	virtual void run();

	static QString xsltTransform( const QString &xmlString, const QCString &xsltString );

	/**
	 * Returns the result string
	 */
	const QString &result()
	{ return m_resultString; };

private:
	QString m_xml;
	QCString m_xsl;
	QString m_resultString;
	QObject *m_target;
	const char *m_slotCompleted;
};

KopeteXSLThread::KopeteXSLThread( const QString &xmlString, const QCString &xsltString, QObject *target, const char *slotCompleted )
{
	m_xml = xmlString;
	m_xsl = xsltString;

	m_target = target;
	m_slotCompleted = slotCompleted;
}

void KopeteXSLThread::run()
{
	m_resultString = xsltTransform( m_xml, m_xsl );

	// Signal completion
	if( m_target && m_slotCompleted )
	{
		QSignal completeSignal( m_target );
		completeSignal.connect( m_target, m_slotCompleted );
		completeSignal.setValue( m_resultString );
		completeSignal.activate();

		// FIXME: Why no 'delete this' if there's no slotCompleted? - Martijn
		delete this;
	}
}

QString KopeteXSLThread::xsltTransform( const QString &xmlString, const QCString &xslCString )
{
	// Init Stuff
	xmlLoadExtDtdDefaultValue = 0;
	xmlSubstituteEntitiesDefault( 1 );

	// Convert QString into a C string
	QCString xmlCString = xmlString.utf8();

	QString resultString;
	QString errorMsg;

	// Read XML docs in from memory
	xmlDocPtr xmlDoc = xmlParseMemory( xmlCString, xmlCString.length() );
	if ( xmlDoc )
	{
		xmlDocPtr xslDoc = xmlParseMemory( xslCString, xslCString.length() );
		if ( xslDoc )
		{
			xsltStylesheetPtr styleSheet = xsltParseStylesheetDoc( xslDoc );
			if ( styleSheet )
			{
				xmlDocPtr resultDoc = xsltApplyStylesheet( styleSheet, xmlDoc, NULL );
				if ( resultDoc )
				{
					// Save the result into the QString
					xmlChar *mem;
					int size;
					xmlDocDumpMemory( resultDoc, &mem, &size );
					resultString = QString::fromUtf8( QCString( ( char * )( mem ), size + 1 ) );
					free( mem );
					xmlFreeDoc( resultDoc );
				}
				else
				{
					errorMsg = i18n( "Transformed document is null!" );
				}
				xsltFreeStylesheet( styleSheet );

				// FIXME: No xmlFreeDoc( xslDoc ) here? - Martijn
			}
			else
			{
				errorMsg = i18n( "Document is not valid XSL!" );
				xmlFreeDoc( xslDoc );
			}
		}
		else
		{
			errorMsg = i18n( "XSL document could not be parsed!" );
		}
		xmlFreeDoc( xmlDoc );
	}
	else
	{
		errorMsg = i18n( "XML document could not be parsed!" );
	}

	if ( resultString.isEmpty() )
		resultString = i18n( "
An internal Kopete error occurred while parsing a message:
%1
" ).arg( errorMsg );

	return resultString;
}

class KopeteXSLTPrivate
{
public:
	QCString document;
};

KopeteXSLT::KopeteXSLT( const QString &document, QObject *parent )
: QObject( parent )
{
	d = new KopeteXSLTPrivate;

	setXSLT( document );
}

KopeteXSLT::~KopeteXSLT()
{
	delete d;
}

void KopeteXSLT::setXSLT( const QString &_document )
{
	// Search for '<kopete-i18n>' elements and feed them through i18n().
	// After that replace the %VAR% variables with their proper XSLT counterpart.
	//
	// FIXME: Preprocessing the document using the QString API is fast and simple,
	//        but also error-sensitive.
	//        In fact, there are a couple of known issues with this algorithm that
	//        depend on the strings in the current styles. If these strings change
	//        they may break the parsing here.
	//
	//        The reason I'm doing it like this is because of issues with QDOM and
	//        namespaces in earlier Qt versions. When we drop Qt 3.1.x support we
	//        should probably convert this to more accurate DOM code. - Martijn
	QRegExp elementMatch( QString::fromLatin1( "<kopete-i18n>(.*)</kopete-i18n>" ) );
	elementMatch.setMinimal( true );
	QString document = _document;
	int pos;
	while ( ( pos = elementMatch.search( document ) ) != -1 )
	{
		QString orig = elementMatch.cap( 1 );
		//kdDebug( 14010 ) << k_funcinfo << "Original text: " << orig << endl;

		// Split on % and go over all parts
		QStringList parts = QStringList::split( '%', i18n( orig.utf8() ), true );

		// The first part is always text, as our variables are written like %FOO%
		QStringList::Iterator it = parts.begin();
		QString trans = *it;
		bool prependPercent = true;
		it = parts.remove( it );
		for ( it = parts.begin(); it != parts.end(); ++it )
		{
			prependPercent = false;
			if ( *it == QString::fromLatin1( "TIME" ) )
			{
				trans += QString::fromLatin1( "<xsl:value-of select=\"@time\"/>" );
			}
			else if ( *it == QString::fromLatin1( "FROM_CONTACT_DISPLAYNAME" ) )
			{
				trans += QString::fromLatin1( "<xsl:attribute name=\"title\">"
					"<xsl:choose>"
						"<xsl:when test='from/contact/@contactId=from/contact/@metaContactDisplayName'>"
							"<xsl:value-of disable-output-escaping=\"yes\" select=\"from/contact/@contactId\"/>"
						"</xsl:when>"
						"<xsl:otherwise>"
							"<xsl:value-of disable-output-escaping=\"yes\" select=\"from/contact/@contactId\"/>"
							" <xsl:value-of disable-output-escaping=\"yes\" select=\"from/contact/@metaContactDisplayName\"/>"
						"</xsl:otherwise>"
					"</xsl:choose></xsl:attribute>"
					"<xsl:value-of disable-output-escaping=\"yes\" select=\"from/contact/@contactDisplayName\"/>" );
			}
			else if ( *it == QString::fromLatin1( "TO_CONTACT_DISPLAYNAME" ) )
			{
				trans += QString::fromLatin1( "<xsl:attribute name=\"title\">"
					"<xsl:choose>"
						"<xsl:when test='to/contact/@contactId=to/contact/@metaContactDisplayName'>"
							"<xsl:value-of disable-output-escaping=\"yes\" select=\"to/contact/@contactId\"/>"
						"</xsl:when>"
						"<xsl:otherwise>"
							"<xsl:value-of disable-output-escaping=\"yes\" select=\"to/contact/@contactId\"/>"
							" <xsl:value-of disable-output-escaping=\"yes\" select=\"to/contact/@metaContactDisplayName\"/>"
						"</xsl:otherwise>"
					"</xsl:choose></xsl:attribute>"
					"<xsl:value-of disable-output-escaping=\"yes\" select=\"to/contact/@contactDisplayName\"/>" );
			}
			else if ( *it == QString::fromLatin1( "FROM_METACONTACT_DISPLAYNAME" ) )
			{
				trans += QString::fromLatin1( "<xsl:value-of disable-output-escaping=\"yes\" select=\"from/contact/@metaContactDisplayName\"/>" );
			}
			else if ( *it == QString::fromLatin1( "TO_METACONTACT_DISPLAYNAME" ) )
			{
				trans += QString::fromLatin1( "<xsl:value-of disable-output-escaping=\"yes\" select=\"to/contact/@metaContactDisplayName\"/>" );
			}
			else if ( *it == QString::fromLatin1( "FROM_CONTACT_ID" ) )
			{
				trans += QString::fromLatin1( "<xsl:attribute name=\"title\">"
					"<xsl:value-of disable-output-escaping=\"yes\" select=\"from/contact/@contactDisplayName\"/></xsl:attribute>"
					"<xsl:value-of disable-output-escaping=\"yes\" select=\"from/contact/@contactId\"/>" );
			}
			else if ( *it == QString::fromLatin1( "TO_CONTACT_ID" ) )
			{
				trans += QString::fromLatin1( "<xsl:attribute name=\"title\">"
					"<xsl:value-of disable-output-escaping=\"yes\" select=\"to/contact/@contactDisplayName\"/></xsl:attribute>"
					"<xsl:value-of disable-output-escaping=\"yes\" select=\"to/contact/@contactId\"/>" );
			}
			else if ( *it == QString::fromLatin1( "BODY" ) )
			{
				trans += QString::fromLatin1( "<xsl:value-of disable-output-escaping=\"yes\" select=\"body\"/>" );
			}
			else
			{
				if ( prependPercent )
					trans += '%';
				trans += *it;
				prependPercent = true;
			}
		}
		//kdDebug( 14010 ) << k_funcinfo << "Translated text: " << trans << endl;
		// Add "<kopete-i18n>" and "</kopete-i18n>" to length, hence the '+ 27'
		document.replace( uint( pos ), orig.length() + 27, trans );
	}
	d->document = document.utf8();
}

QString KopeteXSLT::transform( const QString &xmlString )
{
	return KopeteXSLThread::xsltTransform( xmlString, d->document );
}

void KopeteXSLT::transformAsync( const QString &xmlString, QObject *target, const char *slotCompleted )
{
	( new KopeteXSLThread( xmlString, d->document, target, slotCompleted ) )->start();
}

bool KopeteXSLT::isValid()
{
	bool retVal = false;

	// Init Stuff
	xmlLoadExtDtdDefaultValue = 0;
	xmlSubstituteEntitiesDefault( 1 );

	xmlDocPtr xslDoc = xmlParseMemory( d->document, d->document.length() );
	if ( xslDoc )
	{
		xsltStylesheetPtr styleSheet = xsltParseStylesheetDoc( xslDoc );
		if ( styleSheet )
		{
			retVal = true;
			xsltFreeStylesheet( styleSheet );
		}
		else
		{
			xmlFreeDoc( xslDoc );
		}
	}

	return retVal;
}

#include "kopetexsl.moc"

// vim: set noet ts=4 sts=4 sw=4:

<|endoftext|>