Merge topic 'AutomocForQt'

920a046 QtAutomoc: Eliminate compiler warning
b00463f QtAutomoc test: Pass QT_QMAKE_EXECUTABLE
e78ce44 Fix automoc with VS builds: apply patch from Bill
71165e9 Silence warning in automoc: use long instead of int
1879bcc Fix build: use std::ios::out|ios::trunc instead of std::ios_base::out
678e124 Only enable the automoc test after checking that Qt4 works
71c29d1 Fix bootstrap test with automoc
afb3edc Fix warnings
add30e9 Fix build: non-void function must return a value
7e6d845 Automoc.cmake is not needed anymore
2963d0b Fix logic which decides when to execute automoc test
77a5c6e Add documentation for AUTOMOC, add initialization via CMAKE_AUTOMOC
bf8ef77 Add a test for automoc
d045fd4 Nicer progress message for the automoc target
50cd6ce Move automoc processing from add_executable/library to cmGlobalGenerator
cbaac2a Remove trailing whitespace
c27607b Refactor SetupAutomocTarget() so it can be run after creating the target
24d9b7d Remove trailing whitespace
58b7fe6 Use cout instead of printf()
72caf4d Add the generated automoc.cpp file to the cleaned files
ddb517d Color output when running moc
9303295 Initialize verbose based onb the env.var.
ace1215 Move code for parsing a cpp-file from the big loop to separate function
735a5bb Fix line lengths
83b730c Add AUTOMOC to the add_library() command
126c6ea Add the cmake module required currently for automoc
de91feb Remove the need to check for .h/.cxx during buildtime
d65689a Add actual automoc code from automoc
d1c0a5f Start implementing skeleton for automoc in cmake
a65011b Start work on automoc: add empty cmQtAutomoc class
This commit is contained in:
David Cole 2011-08-25 15:40:29 -04:00 committed by CMake Topic Stage
commit 39f0fa725e
25 changed files with 1917 additions and 74 deletions

View File

@ -0,0 +1,13 @@
set(AM_SOURCES "@_moc_files@" )
set(AM_HEADERS "@_moc_headers@" )
set(AM_MOC_COMPILE_DEFINITIONS "@_moc_compile_defs@")
set(AM_MOC_DEFINITIONS "@_moc_defs@")
set(AM_MOC_INCLUDES "@_moc_incs@")
set(AM_CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE "@CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE@")
set(AM_CMAKE_BINARY_DIR "@CMAKE_BINARY_DIR@/")
set(AM_CMAKE_SOURCE_DIR "@CMAKE_SOURCE_DIR@/")
set(AM_QT_MOC_EXECUTABLE "@QT_MOC_EXECUTABLE@")
set(AM_CMAKE_CURRENT_SOURCE_DIR "@CMAKE_CURRENT_SOURCE_DIR@/")
set(AM_CMAKE_CURRENT_BINARY_DIR "@CMAKE_CURRENT_BINARY_DIR@/")
set(AM_QT_VERSION_MAJOR "@QT_VERSION_MAJOR@" )
set(AM_TARGET_NAME "@_moc_target_name@")

View File

@ -228,6 +228,8 @@ SET(SRCS
cmPropertyDefinitionMap.h
cmPropertyMap.cxx
cmPropertyMap.h
cmQtAutomoc.cxx
cmQtAutomoc.h
cmScriptGenerator.h
cmScriptGenerator.cxx
cmSourceFile.cxx

View File

@ -58,7 +58,8 @@ bool cmAddExecutableCommand
}
// Special modifiers are not allowed with IMPORTED signature.
if(importTarget && (use_win32 || use_macbundle || excludeFromAll))
if(importTarget
&& (use_win32 || use_macbundle || excludeFromAll))
{
if(use_win32)
{

View File

@ -31,13 +31,13 @@ bool cmAddLibraryCommand
}
bool excludeFromAll = false;
bool importTarget = false;
std::vector<std::string>::const_iterator s = args.begin();
std::string libName = *s;
++s;
// If the second argument is "SHARED" or "STATIC", then it controls
// the type of library. Otherwise, it is treated as a source or
// source list name. There may be two keyword arguments, check for them
@ -85,11 +85,11 @@ bool cmAddLibraryCommand
}
}
/* ideally we should check whether for the linker language of the target
/* ideally we should check whether for the linker language of the target
CMAKE_${LANG}_CREATE_SHARED_LIBRARY is defined and if not default to
STATIC. But at this point we know only the name of the target, but not
STATIC. But at this point we know only the name of the target, but not
yet its linker language. */
if ((type != cmTarget::STATIC_LIBRARY) &&
if ((type != cmTarget::STATIC_LIBRARY) &&
(this->Makefile->GetCMakeInstance()->GetPropertyAsBool(
"TARGET_SUPPORTS_SHARED_LIBS") == false))
{
@ -103,16 +103,16 @@ bool cmAddLibraryCommand
type = cmTarget::STATIC_LIBRARY;
}
// The IMPORTED signature requires a type to be specified explicitly.
if(importTarget && !haveSpecifiedType)
{
this->SetError("called with IMPORTED argument but no library type.");
return false;
}
// Handle imported target creation.
if(importTarget)
{
// The IMPORTED signature requires a type to be specified explicitly.
if (!haveSpecifiedType)
{
this->SetError("called with IMPORTED argument but no library type.");
return false;
}
// Make sure the target does not already exist.
if(this->Makefile->FindTargetToUse(libName.c_str()))
{
@ -158,15 +158,14 @@ bool cmAddLibraryCommand
}
std::vector<std::string> srclists;
while (s != args.end())
while (s != args.end())
{
srclists.push_back(*s);
srclists.push_back(*s);
++s;
}
this->Makefile->AddLibrary(libName.c_str(), type, srclists,
excludeFromAll);
this->Makefile->AddLibrary(libName.c_str(), type, srclists, excludeFromAll);
return true;
}

View File

@ -1084,6 +1084,15 @@ void cmDocumentVariables::DefineVariables(cmake* cm)
false,
"Variables that Control the Build");
cm->DefineProperty
("CMAKE_AUTOMOC", cmProperty::VARIABLE,
"Whether to handle moc automatically for Qt targets.",
"This variable is used to initialize the "
"AUTOMOC property on all the targets. "
"See that target property for additional information.",
false,
"Variables that Control the Build");
cm->DefineProperty
("CMAKE_DEBUG_POSTFIX", cmProperty::VARIABLE,
"See variable CMAKE_<CONFIG>_POSTFIX.",

View File

@ -18,6 +18,7 @@
#include "cmExternalMakefileProjectGenerator.h"
#include "cmake.h"
#include "cmMakefile.h"
#include "cmQtAutomoc.h"
#include "cmSourceFile.h"
#include "cmVersion.h"
#include "cmExportInstallFileGenerator.h"
@ -269,7 +270,7 @@ cmGlobalGenerator::EnableLanguage(std::vector<std::string>const& languages,
cmOStringStream windowsVersionString;
windowsVersionString << osvi.dwMajorVersion << "." << osvi.dwMinorVersion;
windowsVersionString.str();
mf->AddDefinition("CMAKE_HOST_SYSTEM_VERSION",
mf->AddDefinition("CMAKE_HOST_SYSTEM_VERSION",
windowsVersionString.str().c_str());
#endif
// Read the DetermineSystem file
@ -618,8 +619,8 @@ void cmGlobalGenerator::SetLanguageEnabledMaps(const char* l, cmMakefile* mf)
if (sscanf(linkerPref, "%d", &preference)!=1)
{
// backward compatibility: before 2.6 LINKER_PREFERENCE
// was either "None" or "Prefered", and only the first character was
// tested. So if there is a custom language out there and it is
// was either "None" or "Prefered", and only the first character was
// tested. So if there is a custom language out there and it is
// "Prefered", set its preference high
if (linkerPref[0]=='P')
{
@ -832,6 +833,10 @@ void cmGlobalGenerator::Generate()
return;
}
// Iterate through all targets and set up automoc for those which have
// the AUTOMOC property set
this->CreateAutomocTargets();
// For each existing cmLocalGenerator
unsigned int i;
@ -950,6 +955,35 @@ bool cmGlobalGenerator::CheckTargets()
return true;
}
//----------------------------------------------------------------------------
void cmGlobalGenerator::CreateAutomocTargets()
{
#ifdef CMAKE_BUILD_WITH_CMAKE
for(unsigned int i=0; i < this->LocalGenerators.size(); ++i)
{
cmTargets& targets =
this->LocalGenerators[i]->GetMakefile()->GetTargets();
for(cmTargets::iterator ti = targets.begin();
ti != targets.end(); ++ti)
{
cmTarget& target = ti->second;
if(target.GetType() == cmTarget::EXECUTABLE ||
target.GetType() == cmTarget::STATIC_LIBRARY ||
target.GetType() == cmTarget::SHARED_LIBRARY ||
target.GetType() == cmTarget::MODULE_LIBRARY)
{
if(target.GetPropertyAsBool("AUTOMOC") && !target.IsImported())
{
cmQtAutomoc automoc;
automoc.SetupAutomocTarget(&target);
}
}
}
}
#endif
}
void cmGlobalGenerator::CheckLocalGenerators()
{
std::map<cmStdString, cmStdString> notFoundMap;
@ -1019,9 +1053,9 @@ void cmGlobalGenerator::CheckLocalGenerators()
if(notFoundMap.size())
{
std::string notFoundVars;
for(std::map<cmStdString, cmStdString>::const_iterator
for(std::map<cmStdString, cmStdString>::const_iterator
ii = notFoundMap.begin();
ii != notFoundMap.end();
ii != notFoundMap.end();
++ii)
{
notFoundVars += ii->first;
@ -1057,7 +1091,7 @@ int cmGlobalGenerator::TryCompile(const char *srcdir, const char *bindir,
{
this->FirstTimeProgress = 0.95f;
}
this->CMakeInstance->UpdateProgress("Configuring",
this->CMakeInstance->UpdateProgress("Configuring",
this->FirstTimeProgress);
}
@ -1161,7 +1195,7 @@ int cmGlobalGenerator::Build(
{
outputPtr = &outputBuffer;
}
// should we do a clean first?
if (clean)
{
@ -1199,7 +1233,7 @@ int cmGlobalGenerator::Build(
// now build
std::string makeCommand =
this->GenerateBuildCommand(makeCommandCSTR, projectName,
extraOptions, target,
extraOptions, target,
config, false, fast);
if(output)
{
@ -1272,8 +1306,8 @@ void cmGlobalGenerator::AddLocalGenerator(cmLocalGenerator *lg)
if(this->FirstTimeProgress > 0.95f)
{
this->FirstTimeProgress = 0.95f;
}
this->CMakeInstance->UpdateProgress("Configuring",
}
this->CMakeInstance->UpdateProgress("Configuring",
this->FirstTimeProgress);
return;
}
@ -1296,8 +1330,8 @@ void cmGlobalGenerator::AddInstallComponent(const char* component)
}
}
void cmGlobalGenerator::AddTargetToExports(const char* exportSetName,
cmTarget* target,
void cmGlobalGenerator::AddTargetToExports(const char* exportSetName,
cmTarget* target,
cmInstallTargetGenerator* archive,
cmInstallTargetGenerator* runTime,
cmInstallTargetGenerator* library,
@ -1331,7 +1365,7 @@ void cmGlobalGenerator::ClearExportSets()
const std::vector<cmTargetExport*>* cmGlobalGenerator::GetExportSet(
const char* name) const
{
std::map<cmStdString, std::vector<cmTargetExport*> >::const_iterator
std::map<cmStdString, std::vector<cmTargetExport*> >::const_iterator
exportSetIt = this->ExportSets.find(name);
if (exportSetIt != this->ExportSets.end())
{
@ -1443,7 +1477,7 @@ void cmGlobalGenerator::GetEnabledLanguages(std::vector<std::string>& lang)
int cmGlobalGenerator::GetLinkerPreference(const char* lang)
{
std::map<cmStdString, int>::const_iterator it =
std::map<cmStdString, int>::const_iterator it =
this->LanguageToLinkerPreference.find(lang);
if (it != this->LanguageToLinkerPreference.end())
{

View File

@ -282,6 +282,8 @@ protected:
virtual bool CheckALLOW_DUPLICATE_CUSTOM_TARGETS();
bool CheckTargets();
void CreateAutomocTargets();
// Fill the ProjectMap, this must be called after LocalGenerators
// has been populated.

View File

@ -739,18 +739,6 @@ void cmGlobalVisualStudio7Generator
entry.Full = "";
}
// make sure "special" targets have GUID's
void cmGlobalVisualStudio7Generator::Configure()
{
cmGlobalGenerator::Configure();
this->CreateGUID("ALL_BUILD");
this->CreateGUID("INSTALL");
this->CreateGUID("RUN_TESTS");
this->CreateGUID("EDIT_CACHE");
this->CreateGUID("REBUILD_CACHE");
this->CreateGUID("PACKAGE");
}
//----------------------------------------------------------------------------
void
cmGlobalVisualStudio7Generator

View File

@ -80,9 +80,6 @@ public:
void CreateGUID(const char* name);
std::string GetGUID(const char* name);
///! do configure step
virtual void Configure();
/** Append the subdirectory for the given configuration. */
virtual void AppendDirectoryForConfig(const char* prefix,
const char* config,

View File

@ -68,6 +68,27 @@ void cmLocalVisualStudio7Generator::AddHelperCommands()
lang.insert("DEF");
lang.insert("Fortran");
this->CreateCustomTargetsAndCommands(lang);
// Now create GUIDs for targets
cmTargets &tgts = this->Makefile->GetTargets();
cmGlobalVisualStudio7Generator* gg =
static_cast<cmGlobalVisualStudio7Generator *>(this->GlobalGenerator);
for(cmTargets::iterator l = tgts.begin(); l != tgts.end(); l++)
{
const char* path = l->second.GetProperty("EXTERNAL_MSPROJECT");
if(path)
{
this->ReadAndStoreExternalGUID(
l->second.GetName(), path);
}
else
{
gg->CreateGUID(l->first.c_str());
}
}
this->FixGlobalTargets();
}
@ -2032,29 +2053,6 @@ void cmLocalVisualStudio7Generator::ReadAndStoreExternalGUID(
}
void cmLocalVisualStudio7Generator::ConfigureFinalPass()
{
cmLocalGenerator::ConfigureFinalPass();
cmTargets &tgts = this->Makefile->GetTargets();
cmGlobalVisualStudio7Generator* gg =
static_cast<cmGlobalVisualStudio7Generator *>(this->GlobalGenerator);
for(cmTargets::iterator l = tgts.begin(); l != tgts.end(); l++)
{
const char* path = l->second.GetProperty("EXTERNAL_MSPROJECT");
if(path)
{
this->ReadAndStoreExternalGUID(
l->second.GetName(), path);
}
else
{
gg->CreateGUID(l->first.c_str());
}
}
}
//----------------------------------------------------------------------------
std::string cmLocalVisualStudio7Generator
::GetTargetDirectory(cmTarget const& target) const

View File

@ -57,7 +57,6 @@ public:
void SetVersion8() {this->Version = 8;}
void SetVersion9() {this->Version = 9;}
void SetPlatformName(const char* n) { this->PlatformName = n;}
virtual void ConfigureFinalPass();
void GetTargetObjectFileDirectories(cmTarget* target,
std::vector<std::string>&
dirs);

View File

@ -1886,7 +1886,7 @@ void cmMakefile::AddGlobalLinkInformation(const char* name, cmTarget& target)
}
void cmMakefile::AddLibrary(const char* lname, cmTarget::TargetType type,
cmTarget* cmMakefile::AddLibrary(const char* lname, cmTarget::TargetType type,
const std::vector<std::string> &srcs,
bool excludeFromAll)
{
@ -1909,6 +1909,7 @@ void cmMakefile::AddLibrary(const char* lname, cmTarget::TargetType type,
}
target->AddSources(srcs);
this->AddGlobalLinkInformation(lname, *target);
return target;
}
cmTarget* cmMakefile::AddExecutable(const char *exeName,

View File

@ -325,7 +325,7 @@ public:
/**
* Set the name of the library.
*/
void AddLibrary(const char *libname, cmTarget::TargetType type,
cmTarget* AddLibrary(const char *libname, cmTarget::TargetType type,
const std::vector<std::string> &srcs,
bool excludeFromAll = false);

782
Source/cmQtAutomoc.cxx Normal file
View File

@ -0,0 +1,782 @@
#include "cmGlobalGenerator.h"
#include "cmLocalGenerator.h"
#include "cmMakefile.h"
#include "cmSourceFile.h"
#include "cmSystemTools.h"
# include <cmsys/Terminal.h>
#include "cmQtAutomoc.h"
cmQtAutomoc::cmQtAutomoc()
:Verbose(cmsys::SystemTools::GetEnv("VERBOSE") != 0)
,ColorOutput(true)
,RunMocFailed(false)
,GenerateAll(false)
{
std::string colorEnv = "";
cmsys::SystemTools::GetEnv("COLOR", colorEnv);
if(!colorEnv.empty())
{
if(cmSystemTools::IsOn(colorEnv.c_str()))
{
this->ColorOutput = true;
}
else
{
this->ColorOutput = false;
}
}
}
void cmQtAutomoc::SetupAutomocTarget(cmTarget* target)
{
cmMakefile* makefile = target->GetMakefile();
const char* targetName = target->GetName();
// don't do anything if there is no Qt4:
std::string qtMajorVersion = makefile->GetSafeDefinition("QT_VERSION_MAJOR");
if (qtMajorVersion != "4")
{
return;
}
// create a custom target for running automoc at buildtime:
std::string automocTargetName = targetName;
automocTargetName += "_automoc";
std::string targetDir = makefile->GetCurrentOutputDirectory();
targetDir += makefile->GetCMakeInstance()->GetCMakeFilesDirectory();
targetDir += "/";
targetDir += automocTargetName;
targetDir += ".dir/";
cmCustomCommandLine currentLine;
currentLine.push_back(makefile->GetCMakeInstance()->GetCMakeCommand());
currentLine.push_back("-E");
currentLine.push_back("cmake_automoc");
currentLine.push_back(targetDir);
cmCustomCommandLines commandLines;
commandLines.push_back(currentLine);
std::string workingDirectory = cmSystemTools::CollapseFullPath(
"", makefile->GetCurrentOutputDirectory());
std::vector<std::string> depends;
std::string automocComment = "Automoc for target ";
automocComment += targetName;
makefile->AddUtilityCommand(automocTargetName.c_str(), true,
workingDirectory.c_str(), depends,
commandLines, false, automocComment.c_str());
target->AddUtility(automocTargetName.c_str());
// configure a file to get all information to automoc at buildtime:
std::string _moc_files;
std::string _moc_headers;
const char* sepFiles = "";
const char* sepHeaders = "";
const std::vector<cmSourceFile*>& srcFiles = target->GetSourceFiles();
for(std::vector<cmSourceFile*>::const_iterator fileIt = srcFiles.begin();
fileIt != srcFiles.end();
++fileIt)
{
cmSourceFile* sf = *fileIt;
std::string absFile = sf->GetFullPath();
bool skip = cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTOMOC"));
bool generated = cmSystemTools::IsOn(sf->GetPropertyForUser("GENERATED"));
if ((skip==false) && (generated == false))
{
std::string ext = sf->GetExtension();
cmSystemTools::FileFormat fileType = cmSystemTools::GetFileFormat(
ext.c_str());
if (fileType == cmSystemTools::CXX_FILE_FORMAT)
{
_moc_files += sepFiles;
_moc_files += absFile;
sepFiles = ";";
}
else if (fileType == cmSystemTools::HEADER_FILE_FORMAT)
{
_moc_headers += sepHeaders;
_moc_headers += absFile;
sepHeaders = ";";
}
}
}
std::string _moc_incs = makefile->GetProperty("INCLUDE_DIRECTORIES");
std::string _moc_defs = makefile->GetProperty("DEFINITIONS");
std::string _moc_compile_defs = makefile->GetProperty("COMPILE_DEFINITIONS");
// forget the variables added here afterwards again:
cmMakefile::ScopePushPop varScope(makefile);
static_cast<void>(varScope);
makefile->AddDefinition("_moc_target_name", automocTargetName.c_str());
makefile->AddDefinition("_moc_incs", _moc_incs.c_str());
makefile->AddDefinition("_moc_defs", _moc_defs.c_str());
makefile->AddDefinition("_moc_compile_defs", _moc_compile_defs.c_str());
makefile->AddDefinition("_moc_files", _moc_files.c_str());
makefile->AddDefinition("_moc_headers", _moc_headers.c_str());
const char* cmakeRoot = makefile->GetDefinition("CMAKE_ROOT");
std::string inputFile = cmakeRoot;
inputFile += "/Modules/AutomocInfo.cmake.in";
std::string outputFile = targetDir;
outputFile += "/AutomocInfo.cmake";
makefile->ConfigureFile(inputFile.c_str(), outputFile.c_str(),
false, true, false);
std::string mocCppFile = makefile->GetCurrentOutputDirectory();
mocCppFile += "/";
mocCppFile += automocTargetName;
mocCppFile += ".cpp";
cmSourceFile* mocCppSource = makefile->GetOrCreateSource(mocCppFile.c_str(),
true);
target->AddSourceFile(mocCppSource);
makefile->AppendProperty("ADDITIONAL_MAKE_CLEAN_FILES",
mocCppFile.c_str(), false);
}
bool cmQtAutomoc::Run(const char* targetDirectory)
{
cmake cm;
cmGlobalGenerator* gg = this->CreateGlobalGenerator(&cm, targetDirectory);
cmMakefile* makefile = gg->GetCurrentLocalGenerator()->GetMakefile();
this->ReadAutomocInfoFile(makefile, targetDirectory);
this->ReadOldMocDefinitionsFile(makefile, targetDirectory);
this->Init();
if (this->QtMajorVersion == "4")
{
this->RunAutomocQt4();
}
this->WriteOldMocDefinitionsFile(targetDirectory);
delete gg;
gg = NULL;
makefile = NULL;
return true;
}
cmGlobalGenerator* cmQtAutomoc::CreateGlobalGenerator(cmake* cm,
const char* targetDirectory)
{
cmGlobalGenerator* gg = new cmGlobalGenerator();
gg->SetCMakeInstance(cm);
cmLocalGenerator* lg = gg->CreateLocalGenerator();
lg->GetMakefile()->SetHomeOutputDirectory(targetDirectory);
lg->GetMakefile()->SetStartOutputDirectory(targetDirectory);
lg->GetMakefile()->SetHomeDirectory(targetDirectory);
lg->GetMakefile()->SetStartDirectory(targetDirectory);
gg->SetCurrentLocalGenerator(lg);
return gg;
}
bool cmQtAutomoc::ReadAutomocInfoFile(cmMakefile* makefile,
const char* targetDirectory)
{
std::string filename(cmSystemTools::CollapseFullPath(targetDirectory));
cmSystemTools::ConvertToUnixSlashes(filename);
filename += "/AutomocInfo.cmake";
if (!makefile->ReadListFile(0, filename.c_str()))
{
cmSystemTools::Error("Error processing file:", filename.c_str());
return false;
}
this->QtMajorVersion = makefile->GetSafeDefinition("AM_QT_VERSION_MAJOR");
this->Sources = makefile->GetSafeDefinition("AM_SOURCES");
this->Headers = makefile->GetSafeDefinition("AM_HEADERS");
this->IncludeProjectDirsBefore = makefile->IsOn(
"AM_CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE");
this->Srcdir = makefile->GetSafeDefinition("AM_CMAKE_CURRENT_SOURCE_DIR");
this->Builddir = makefile->GetSafeDefinition("AM_CMAKE_BINARY_DIR");
this->MocExecutable = makefile->GetSafeDefinition("AM_QT_MOC_EXECUTABLE");
this->MocCompileDefinitionsStr = makefile->GetSafeDefinition(
"AM_MOC_COMPILE_DEFINITIONS");
this->MocDefinitionsStr = makefile->GetSafeDefinition("AM_MOC_DEFINITIONS");
this->MocIncludesStr = makefile->GetSafeDefinition("AM_MOC_INCLUDES");
this->ProjectBinaryDir = makefile->GetSafeDefinition("AM_CMAKE_BINARY_DIR");
this->ProjectSourceDir = makefile->GetSafeDefinition("AM_CMAKE_SOURCE_DIR");
this->TargetName = makefile->GetSafeDefinition("AM_TARGET_NAME");
return true;
}
bool cmQtAutomoc::ReadOldMocDefinitionsFile(cmMakefile* makefile,
const char* targetDirectory)
{
std::string filename(cmSystemTools::CollapseFullPath(targetDirectory));
cmSystemTools::ConvertToUnixSlashes(filename);
filename += "/AutomocOldMocDefinitions.cmake";
if (makefile->ReadListFile(0, filename.c_str()))
{
this->OldMocDefinitionsStr =
makefile->GetSafeDefinition("AM_OLD_MOC_DEFINITIONS");
}
return true;
}
void cmQtAutomoc::WriteOldMocDefinitionsFile(const char* targetDirectory)
{
std::string filename(cmSystemTools::CollapseFullPath(targetDirectory));
cmSystemTools::ConvertToUnixSlashes(filename);
filename += "/AutomocOldMocDefinitions.cmake";
std::fstream outfile;
outfile.open(filename.c_str(),
std::ios::out | std::ios::trunc);
outfile << "set(AM_OLD_MOC_DEFINITIONS \""
<< this->Join(this->MocDefinitions, ' ') << "\")\n";
outfile.close();
}
void cmQtAutomoc::Init()
{
this->OutMocCppFilename = this->Builddir;
this->OutMocCppFilename += this->TargetName;
this->OutMocCppFilename += ".cpp";
std::vector<std::string> cdefList;
cmSystemTools::ExpandListArgument(this->MocCompileDefinitionsStr, cdefList);
if (!cdefList.empty())
{
for(std::vector<std::string>::const_iterator it = cdefList.begin();
it != cdefList.end();
++it)
{
this->MocDefinitions.push_back("-D" + (*it));
}
}
else
{
std::string tmpMocDefs = this->MocDefinitionsStr;
cmSystemTools::ReplaceString(tmpMocDefs, " ", ";");
std::vector<std::string> defList;
cmSystemTools::ExpandListArgument(tmpMocDefs, defList);
for(std::vector<std::string>::const_iterator it = defList.begin();
it != defList.end();
++it)
{
if (this->StartsWith(*it, "-D"))
{
this->MocDefinitions.push_back(*it);
}
}
}
std::vector<std::string> incPaths;
cmSystemTools::ExpandListArgument(this->MocIncludesStr, incPaths);
std::set<std::string> frameworkPaths;
for(std::vector<std::string>::const_iterator it = incPaths.begin();
it != incPaths.end();
++it)
{
const std::string &path = *it;
this->MocIncludes.push_back("-I" + path);
if (this->EndsWith(path, ".framework/Headers"))
{
// Go up twice to get to the framework root
std::vector<std::string> pathComponents;
cmsys::SystemTools::SplitPath(path.c_str(), pathComponents);
std::string frameworkPath =cmsys::SystemTools::JoinPath(
pathComponents.begin(), pathComponents.end() - 2);
frameworkPaths.insert(frameworkPath);
}
}
for (std::set<std::string>::const_iterator it = frameworkPaths.begin();
it != frameworkPaths.end(); ++it)
{
this->MocIncludes.push_back("-F");
this->MocIncludes.push_back(*it);
}
if (this->IncludeProjectDirsBefore)
{
const std::string &binDir = "-I" + this->ProjectBinaryDir;
const std::string srcDir = "-I" + this->ProjectSourceDir;
std::list<std::string> sortedMocIncludes;
std::list<std::string>::iterator it = this->MocIncludes.begin();
while (it != this->MocIncludes.end())
{
if (this->StartsWith(*it, binDir))
{
sortedMocIncludes.push_back(*it);
it = this->MocIncludes.erase(it);
}
else
{
++it;
}
}
it = this->MocIncludes.begin();
while (it != this->MocIncludes.end())
{
if (this->StartsWith(*it, srcDir))
{
sortedMocIncludes.push_back(*it);
it = this->MocIncludes.erase(it);
}
else
{
++it;
}
}
sortedMocIncludes.insert(sortedMocIncludes.end(),
this->MocIncludes.begin(), this->MocIncludes.end());
this->MocIncludes = sortedMocIncludes;
}
}
bool cmQtAutomoc::RunAutomocQt4()
{
if (!cmsys::SystemTools::FileExists(this->OutMocCppFilename.c_str())
|| (this->OldMocDefinitionsStr != this->Join(this->MocDefinitions, ' ')))
{
this->GenerateAll = true;
}
// the program goes through all .cpp files to see which moc files are
// included. It is not really interesting how the moc file is named, but
// what file the moc is created from. Once a moc is included the same moc
// may not be included in the _automoc.cpp file anymore. OTOH if there's a
// header containing Q_OBJECT where no corresponding moc file is included
// anywhere a moc_<filename>.cpp file is created and included in
// the _automoc.cpp file.
// key = moc source filepath, value = moc output filepath
std::map<std::string, std::string> includedMocs;
// key = moc source filepath, value = moc output filename
std::map<std::string, std::string> notIncludedMocs;
std::vector<std::string> sourceFiles;
cmSystemTools::ExpandListArgument(this->Sources, sourceFiles);
for (std::vector<std::string>::const_iterator it = sourceFiles.begin();
it != sourceFiles.end();
++it)
{
const std::string &absFilename = *it;
if (this->Verbose)
{
std::cout << "AUTOMOC: Checking " << absFilename << std::endl;
}
this->ParseCppFile(absFilename, includedMocs, notIncludedMocs);
}
std::vector<std::string> headerFiles;
cmSystemTools::ExpandListArgument(this->Headers, headerFiles);
for (std::vector<std::string>::const_iterator it = headerFiles.begin();
it != headerFiles.end();
++it)
{
const std::string &absFilename = *it;
if (this->Verbose)
{
std::cout << "AUTOMOC: Checking " << absFilename << std::endl;
}
if (includedMocs.find(absFilename) == includedMocs.end()
&& notIncludedMocs.find(absFilename) == notIncludedMocs.end())
{
// if this header is not getting processed yet and is explicitly
// mentioned for the automoc the moc is run unconditionally on the
// header and the resulting file is included in the _automoc.cpp file
// (unless there's a .cpp file later on that includes the moc from
// this header)
const std::string currentMoc = "moc_" + cmsys::SystemTools::
GetFilenameWithoutLastExtension(absFilename) + ".cpp";
notIncludedMocs[absFilename] = currentMoc;
}
}
// run moc on all the moc's that are #included in source files
for(std::map<std::string, std::string>::const_iterator
it = includedMocs.begin();
it != includedMocs.end();
++it)
{
this->GenerateMoc(it->first, it->second);
}
std::stringstream outStream(std::stringstream::out);
outStream << "/* This file is autogenerated, do not edit*/\n";
bool automocCppChanged = false;
if (notIncludedMocs.empty())
{
outStream << "enum some_compilers { need_more_than_nothing };\n";
}
else
{
// run moc on the remaining headers and include them in
// the _automoc.cpp file
for(std::map<std::string, std::string>::const_iterator
it = notIncludedMocs.begin();
it != notIncludedMocs.end();
++it)
{
bool mocSuccess = this->GenerateMoc(it->first, it->second);
if (mocSuccess)
{
automocCppChanged = true;
}
outStream << "#include \"" << it->second << "\"\n";
}
}
if (this->RunMocFailed)
{
std::cerr << "returning failed.."<< std::endl;
return false;
}
outStream.flush();
std::string automocSource = outStream.str();
if (!automocCppChanged)
{
// compare contents of the _automoc.cpp file
const std::string oldContents = this->ReadAll(this->OutMocCppFilename);
if (oldContents == automocSource)
{
// nothing changed: don't touch the _automoc.cpp file
return true;
}
}
// source file that includes all remaining moc files (_automoc.cpp file)
std::fstream outfile;
outfile.open(this->OutMocCppFilename.c_str(),
std::ios::out | std::ios::trunc);
outfile << automocSource;
outfile.close();
return true;
}
void cmQtAutomoc::ParseCppFile(const std::string& absFilename,
std::map<std::string, std::string>& includedMocs,
std::map<std::string, std::string>& notIncludedMocs)
{
cmsys::RegularExpression mocIncludeRegExp(
"[\n][ \t]*#[ \t]*include[ \t]+"
"[\"<](([^ \">]+/)?moc_[^ \">/]+\\.cpp|[^ \">]+\\.moc)[\">]");
cmsys::RegularExpression qObjectRegExp("[\n][ \t]*Q_OBJECT[^a-zA-Z0-9_]");
std::list<std::string> headerExtensions;
headerExtensions.push_back(".h");
headerExtensions.push_back(".hpp");
headerExtensions.push_back(".hxx");
#if defined(_WIN32)
// not case sensitive, don't add ".H"
#elif defined(__APPLE__)
// detect case-sensitive filesystem
long caseSensitive = pathconf(this->Srcdir.c_str(), _PC_CASE_SENSITIVE);
if (caseSensitive == 1)
{
headerExtensions.push_back(".H");
}
#else
headerExtensions.push_back(".H");
#endif
const std::string contentsString = this->ReadAll(absFilename);
if (contentsString.empty())
{
std::cerr << "AUTOMOC: empty source file: " << absFilename << std::endl;
return;
}
const std::string absPath = cmsys::SystemTools::GetFilenamePath(
cmsys::SystemTools::GetRealPath(absFilename.c_str())) + '/';
std::string::size_type matchOffset = 0;
if (!mocIncludeRegExp.find(contentsString.c_str()))
{
// no moc #include, look whether we need to create a moc from
// the .h nevertheless
const std::string basename =
cmsys::SystemTools::GetFilenameWithoutLastExtension(absFilename);
for(std::list<std::string>::const_iterator ext = headerExtensions.begin();
ext != headerExtensions.end();
++ext)
{
const std::string headername = absPath + basename + (*ext);
if (cmsys::SystemTools::FileExists(headername.c_str())
&& includedMocs.find(headername) == includedMocs.end()
&& notIncludedMocs.find(headername) == notIncludedMocs.end())
{
const std::string currentMoc = "moc_" + basename + ".cpp";
const std::string contents = this->ReadAll(headername);
if (qObjectRegExp.find(contents))
{
//std::cout << "header contains Q_OBJECT macro";
notIncludedMocs[headername] = currentMoc;
}
break;
}
}
for(std::list<std::string>::const_iterator ext = headerExtensions.begin();
ext != headerExtensions.end();
++ext)
{
const std::string privateHeaderName = absPath+basename+"_p"+(*ext);
if (cmsys::SystemTools::FileExists(privateHeaderName.c_str())
&& includedMocs.find(privateHeaderName) == includedMocs.end()
&& notIncludedMocs.find(privateHeaderName) == notIncludedMocs.end())
{
const std::string currentMoc = "moc_" + basename + "_p.cpp";
const std::string contents = this->ReadAll(privateHeaderName);
if (qObjectRegExp.find(contents))
{
//std::cout << "header contains Q_OBJECT macro";
notIncludedMocs[privateHeaderName] = currentMoc;
}
break;
}
}
}
else
{
// for every moc include in the file
do
{
const std::string currentMoc = mocIncludeRegExp.match(1);
//std::cout << "found moc include: " << currentMoc << std::endl;
std::string basename = cmsys::SystemTools::
GetFilenameWithoutLastExtension(currentMoc);
const bool moc_style = this->StartsWith(basename, "moc_");
// If the moc include is of the moc_foo.cpp style we expect
// the Q_OBJECT class declaration in a header file.
// If the moc include is of the foo.moc style we need to look for
// a Q_OBJECT macro in the current source file, if it contains the
// macro we generate the moc file from the source file, else from the
// header.
// Q_OBJECT
if (moc_style || !qObjectRegExp.find(contentsString))
{
if (moc_style)
{
// basename should be the part of the moc filename used for
// finding the correct header, so we need to remove the moc_ part
basename = basename.substr(4);
}
bool headerFound = false;
for(std::list<std::string>::const_iterator ext =
headerExtensions.begin();
ext != headerExtensions.end();
++ext)
{
const std::string &sourceFilePath = absPath + basename + (*ext);
if (cmsys::SystemTools::FileExists(sourceFilePath.c_str()))
{
headerFound = true;
includedMocs[sourceFilePath] = currentMoc;
notIncludedMocs.erase(sourceFilePath);
break;
}
}
if (!headerFound)
{
// the moc file is in a subdir => look for the header in the
// same subdir
if (currentMoc.find_first_of('/') != std::string::npos)
{
const std::string &filepath = absPath
+ cmsys::SystemTools::GetFilenamePath(currentMoc)
+ '/' + basename;
for(std::list<std::string>::const_iterator ext =
headerExtensions.begin();
ext != headerExtensions.end();
++ext)
{
const std::string &sourceFilePath = filepath + (*ext);
if (cmsys::SystemTools::FileExists(sourceFilePath.c_str()))
{
headerFound = true;
includedMocs[sourceFilePath] = currentMoc;
notIncludedMocs.erase(sourceFilePath);
break;
}
}
if (!headerFound)
{
std::cerr << "AUTOMOC: The file \"" << absFilename
<< "\" includes the moc file \"" << currentMoc
<< "\", but neither \"" << absPath << basename
<< '{' << this->Join(headerExtensions, ',')
<< "}\" nor \"" << filepath << '{'
<< this->Join(headerExtensions, ',') << '}'
<< "\" exist." << std::endl;
::exit(EXIT_FAILURE);
}
}
else
{
std::cerr << "AUTOMOC: The file \"" << absFilename
<< "\" includes the moc file \"" << currentMoc
<< "\", but \"" << absPath << basename << '{'
<< this->Join(headerExtensions, ',') << '}'
<< "\" does not exist." << std::endl;
::exit(EXIT_FAILURE);
}
}
}
else
{
includedMocs[absFilename] = currentMoc;
notIncludedMocs.erase(absFilename);
}
matchOffset += mocIncludeRegExp.end();
} while(mocIncludeRegExp.find(contentsString.c_str() + matchOffset));
}
}
bool cmQtAutomoc::GenerateMoc(const std::string& sourceFile,
const std::string& mocFileName)
{
const std::string mocFilePath = this->Builddir + mocFileName;
int sourceNewerThanMoc = 0;
bool success = cmsys::SystemTools::FileTimeCompare(sourceFile.c_str(),
mocFilePath.c_str(),
&sourceNewerThanMoc);
if (this->GenerateAll || !success || sourceNewerThanMoc >= 0)
{
// make sure the directory for the resulting moc file exists
std::string mocDir = mocFilePath.substr(0, mocFilePath.rfind('/'));
if (!cmsys::SystemTools::FileExists(mocDir.c_str(), false))
{
cmsys::SystemTools::MakeDirectory(mocDir.c_str());
}
std::string msg = "Generating ";
msg += mocFileName;
cmSystemTools::MakefileColorEcho(cmsysTerminal_Color_ForegroundBlue
|cmsysTerminal_Color_ForegroundBold,
msg.c_str(), true, this->ColorOutput);
std::vector<cmStdString> command;
command.push_back(this->MocExecutable);
for (std::list<std::string>::const_iterator it = this->MocIncludes.begin();
it != this->MocIncludes.end();
++it)
{
command.push_back(*it);
}
for(std::list<std::string>::const_iterator it=this->MocDefinitions.begin();
it != this->MocDefinitions.end();
++it)
{
command.push_back(*it);
}
#ifdef _WIN32
command.push_back("-DWIN32");
#endif
command.push_back("-o");
command.push_back(mocFilePath);
command.push_back(sourceFile);
if (this->Verbose)
{
for(std::vector<cmStdString>::const_iterator cmdIt = command.begin();
cmdIt != command.end();
++cmdIt)
{
std::cout << *cmdIt << " ";
}
std::cout << std::endl;
}
std::string output;
int retVal = 0;
bool result = cmSystemTools::RunSingleCommand(command, &output, &retVal);
if (!result || retVal)
{
std::cerr << "AUTOMOC: process for " << mocFilePath << " failed:\n"
<< output << std::endl;
this->RunMocFailed = true;
cmSystemTools::RemoveFile(mocFilePath.c_str());
}
return true;
}
return false;
}
std::string cmQtAutomoc::Join(const std::list<std::string>& lst,char separator)
{
if (lst.empty())
{
return "";
}
std::string result;
for (std::list<std::string>::const_iterator it = lst.begin();
it != lst.end();
++it)
{
result += (*it) + separator;
}
result.erase(result.end() - 1);
return result;
}
bool cmQtAutomoc::StartsWith(const std::string& str, const std::string& with)
{
return (str.substr(0, with.length()) == with);
}
bool cmQtAutomoc::EndsWith(const std::string& str, const std::string& with)
{
if (with.length() > (str.length()))
{
return false;
}
return (str.substr(str.length() - with.length(), with.length()) == with);
}
std::string cmQtAutomoc::ReadAll(const std::string& filename)
{
std::ifstream file(filename.c_str());
std::stringstream stream;
stream << file.rdbuf();
file.close();
return stream.str();
}

66
Source/cmQtAutomoc.h Normal file
View File

@ -0,0 +1,66 @@
#ifndef cmQtAutomoc_h
#define cmQtAutomoc_h
class cmGlobalGenerator;
class cmMakefile;
class cmQtAutomoc
{
public:
cmQtAutomoc();
bool Run(const char* targetDirectory);
void SetupAutomocTarget(cmTarget* target);
private:
cmGlobalGenerator* CreateGlobalGenerator(cmake* cm,
const char* targetDirectory);
bool ReadAutomocInfoFile(cmMakefile* makefile,
const char* targetDirectory);
bool ReadOldMocDefinitionsFile(cmMakefile* makefile,
const char* targetDirectory);
void WriteOldMocDefinitionsFile(const char* targetDirectory);
bool RunAutomocQt4();
bool GenerateMoc(const std::string& sourceFile,
const std::string& mocFileName);
void ParseCppFile(const std::string& absFilename,
std::map<std::string, std::string>& includedMocs,
std::map<std::string, std::string>& notIncludedMocs);
void Init();
std::string Join(const std::list<std::string>& lst, char separator);
bool EndsWith(const std::string& str, const std::string& with);
bool StartsWith(const std::string& str, const std::string& with);
std::string ReadAll(const std::string& filename);
std::string QtMajorVersion;
std::string Sources;
std::string Headers;
bool IncludeProjectDirsBefore;
std::string Srcdir;
std::string Builddir;
std::string MocExecutable;
std::string MocCompileDefinitionsStr;
std::string MocDefinitionsStr;
std::string MocIncludesStr;
std::string ProjectBinaryDir;
std::string ProjectSourceDir;
std::string TargetName;
std::string OldMocDefinitionsStr;
std::string OutMocCppFilename;
std::list<std::string> MocIncludes;
std::list<std::string> MocDefinitions;
bool Verbose;
bool ColorOutput;
bool RunMocFailed;
bool GenerateAll;
};
#endif

View File

@ -114,6 +114,28 @@ cmTarget::cmTarget()
//----------------------------------------------------------------------------
void cmTarget::DefineProperties(cmake *cm)
{
cm->DefineProperty
("AUTOMOC", cmProperty::TARGET,
"Should the target be processed with automoc (for Qt projects).",
"AUTOMOC is a boolean specifying whether CMake will handle "
"the Qt moc preprocessor automatically, i.e. without having to use "
"the QT4_WRAP_CPP() macro. Currently Qt4 is supported. "
"When this property is set to TRUE, CMake will scan the source files "
"at build time and invoke moc accordingly. "
"If an #include statement like #include \"moc_foo.cpp\" is found, "
"the Q_OBJECT class declaration is expected in the header, and moc is "
"run on the header file. "
"If an #include statement like #include \"foo.moc\" is found, "
"then a Q_OBJECT is expected in the current source file and moc "
"is run on the file itself. "
"Additionally, all header files are parsed for Q_OBJECT macros, "
"and if found, moc is also executed on those files. The resulting "
"moc files, which are not included as shown above in any of the source "
"files are included in a generated <targetname>_automoc.cpp file, "
"which is compiled as part of the target."
"This property is initialized by the value of the variable "
"CMAKE_AUTOMOC if it is set when a target is created.");
cm->DefineProperty
("BUILD_WITH_INSTALL_RPATH", cmProperty::TARGET,
"Should build tree targets have install tree rpaths.",
@ -1118,6 +1140,7 @@ void cmTarget::SetMakefile(cmMakefile* mf)
this->SetPropertyDefault("RUNTIME_OUTPUT_DIRECTORY", 0);
this->SetPropertyDefault("Fortran_MODULE_DIRECTORY", 0);
this->SetPropertyDefault("OSX_ARCHITECTURES", 0);
this->SetPropertyDefault("AUTOMOC", 0);
// Collect the set of configuration types.
std::vector<std::string> configNames;
@ -1420,7 +1443,7 @@ bool cmTargetTraceDependencies::IsUtility(std::string const& dep)
// the fact that the name matched a target was just a coincidence.
if(cmSystemTools::FileIsFullPath(dep.c_str()))
{
if(t->GetType() >= cmTarget::EXECUTABLE &&
if(t->GetType() >= cmTarget::EXECUTABLE &&
t->GetType() <= cmTarget::MODULE_LIBRARY)
{
// This is really only for compatibility so we do not need to

View File

@ -20,6 +20,7 @@
#include "cmCommand.h"
#include "cmFileTimeComparison.h"
#include "cmGeneratedFileStream.h"
#include "cmQtAutomoc.h"
#include "cmSourceFile.h"
#include "cmVersion.h"
#include "cmTest.h"
@ -1572,6 +1573,12 @@ int cmake::ExecuteCMakeCommand(std::vector<std::string>& args)
{
return cmake::ExecuteEchoColor(args);
}
else if (args[1] == "cmake_automoc")
{
cmQtAutomoc automoc;
automoc.Run(args[2].c_str());
return 0;
}
#endif
// Tar files
@ -2919,6 +2926,13 @@ const char* cmake::GetCPackCommand()
return this->CPackCommand.c_str();
}
const char* cmake::GetCMakeCommand()
{
return this->CMakeCommand.c_str();
}
void cmake::MarkCliAsUsed(const std::string& variable)
{
this->UsedCliVariables[variable] = true;

View File

@ -301,6 +301,7 @@ class cmake
*/
const char* GetCTestCommand();
const char* GetCPackCommand();
const char* GetCMakeCommand();
// Do we want debug output during the cmake run.
bool GetDebugOutput() { return this->DebugOutput; }

View File

@ -845,6 +845,45 @@ ${CMake_BINARY_DIR}/bin/cmake -DVERSION=master -P ${CMake_SOURCE_DIR}/Utilities/
)
LIST(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/Environment")
IF(NOT QT4_FOUND)
FIND_PACKAGE(Qt4)
ENDIF(NOT QT4_FOUND)
IF(QT4_FOUND)
# test whether the Qt4 which has been found works, on some machines
# which run nightly builds there were errors like "wrong file format"
# for libQtCore.so. So first check it works, and only if it does add
# the automoc test.
INCLUDE(CheckCXXSourceCompiles)
SET(_save_CMAKE_REQUIRED_INCLUDES "${CMAKE_REQUIRED_INCLUDES}")
SET(_save_CMAKE_REQUIRED_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES}")
SET(CMAKE_REQUIRED_INCLUDES ${QT_INCLUDES})
SET(CMAKE_REQUIRED_LIBRARIES ${QT_QTCORE_LIBRARIES})
CHECK_CXX_SOURCE_COMPILES("#include <QCoreApplication>\n int main() {return (qApp == 0 ? 0 : 1); }\n"
QT4_WORKS_FOR_AUTOMOC_TEST)
SET(CMAKE_REQUIRED_INCLUDES "${_save_CMAKE_REQUIRED_INCLUDES}")
SET(CMAKE_REQUIRED_LIBRARIES "${_save_CMAKE_REQUIRED_LIBRARIES}")
IF(QT4_WORKS_FOR_AUTOMOC_TEST)
ADD_TEST(QtAutomoc ${CMAKE_CTEST_COMMAND}
--build-and-test
"${CMake_SOURCE_DIR}/Tests/QtAutomoc"
"${CMake_BINARY_DIR}/Tests/QtAutomoc"
--build-generator ${CMAKE_TEST_GENERATOR}
--build-project QtAutomoc
--build-makeprogram ${CMAKE_TEST_MAKEPROGRAM}
--build-exe-dir "${CMake_BINARY_DIR}/Tests/QtAutomoc"
--force-new-ctest-process
--build-options -DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE}
--test-command ${CMAKE_CTEST_COMMAND} -V
)
LIST(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/QtAutomoc")
ENDIF()
ENDIF()
ADD_TEST(ExternalProject ${CMAKE_CTEST_COMMAND}
--build-and-test
"${CMake_SOURCE_DIR}/Tests/ExternalProject"

View File

@ -0,0 +1,20 @@
cmake_minimum_required(VERSION 2.8)
project(QtAutomoc)
find_package(Qt4 REQUIRED)
include(UseQt4)
include_directories(${CMAKE_CURRENT_BINARY_DIR})
add_definitions(-DFOO)
# create an executable and a library target, both requiring automoc:
add_library(codeeditorLib STATIC codeeditor.cpp)
add_executable(foo main.cpp calwidget.cpp )
set_target_properties(foo codeeditorLib PROPERTIES AUTOMOC TRUE)
target_link_libraries(foo codeeditorLib ${QT_LIBRARIES} )

View File

@ -0,0 +1,424 @@
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
** the names of its contributors may be used to endorse or promote
** products derived from this software without specific prior written
** permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** 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."
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QtGui>
#include "calwidget.h"
Window::Window()
{
createPreviewGroupBox();
createGeneralOptionsGroupBox();
createDatesGroupBox();
createTextFormatsGroupBox();
QGridLayout *layout = new QGridLayout;
layout->addWidget(previewGroupBox, 0, 0);
layout->addWidget(generalOptionsGroupBox, 0, 1);
layout->addWidget(datesGroupBox, 1, 0);
layout->addWidget(textFormatsGroupBox, 1, 1);
layout->setSizeConstraint(QLayout::SetFixedSize);
setLayout(layout);
previewLayout->setRowMinimumHeight(0, calendar->sizeHint().height());
previewLayout->setColumnMinimumWidth(0, calendar->sizeHint().width());
setWindowTitle(tr("Calendar Widget"));
}
void Window::localeChanged(int index)
{
calendar->setLocale(localeCombo->itemData(index).toLocale());
}
void Window::firstDayChanged(int index)
{
calendar->setFirstDayOfWeek(Qt::DayOfWeek(
firstDayCombo->itemData(index).toInt()));
}
void Window::selectionModeChanged(int index)
{
calendar->setSelectionMode(QCalendarWidget::SelectionMode(
selectionModeCombo->itemData(index).toInt()));
}
void Window::horizontalHeaderChanged(int index)
{
calendar->setHorizontalHeaderFormat(QCalendarWidget::HorizontalHeaderFormat(
horizontalHeaderCombo->itemData(index).toInt()));
}
void Window::verticalHeaderChanged(int index)
{
calendar->setVerticalHeaderFormat(QCalendarWidget::VerticalHeaderFormat(
verticalHeaderCombo->itemData(index).toInt()));
}
void Window::selectedDateChanged()
{
currentDateEdit->setDate(calendar->selectedDate());
}
void Window::minimumDateChanged(const QDate &date)
{
calendar->setMinimumDate(date);
maximumDateEdit->setDate(calendar->maximumDate());
}
void Window::maximumDateChanged(const QDate &date)
{
calendar->setMaximumDate(date);
minimumDateEdit->setDate(calendar->minimumDate());
}
void Window::weekdayFormatChanged()
{
QTextCharFormat format;
format.setForeground(qvariant_cast<QColor>(
weekdayColorCombo->itemData(weekdayColorCombo->currentIndex())));
calendar->setWeekdayTextFormat(Qt::Monday, format);
calendar->setWeekdayTextFormat(Qt::Tuesday, format);
calendar->setWeekdayTextFormat(Qt::Wednesday, format);
calendar->setWeekdayTextFormat(Qt::Thursday, format);
calendar->setWeekdayTextFormat(Qt::Friday, format);
}
void Window::weekendFormatChanged()
{
QTextCharFormat format;
format.setForeground(qvariant_cast<QColor>(
weekendColorCombo->itemData(weekendColorCombo->currentIndex())));
calendar->setWeekdayTextFormat(Qt::Saturday, format);
calendar->setWeekdayTextFormat(Qt::Sunday, format);
}
void Window::reformatHeaders()
{
QString text = headerTextFormatCombo->currentText();
QTextCharFormat format;
if (text == tr("Bold")) {
format.setFontWeight(QFont::Bold);
} else if (text == tr("Italic")) {
format.setFontItalic(true);
} else if (text == tr("Green")) {
format.setForeground(Qt::green);
}
calendar->setHeaderTextFormat(format);
}
void Window::reformatCalendarPage()
{
if (firstFridayCheckBox->isChecked()) {
QDate firstFriday(calendar->yearShown(), calendar->monthShown(), 1);
while (firstFriday.dayOfWeek() != Qt::Friday)
firstFriday = firstFriday.addDays(1);
QTextCharFormat firstFridayFormat;
firstFridayFormat.setForeground(Qt::blue);
calendar->setDateTextFormat(firstFriday, firstFridayFormat);
}
//May First in Red takes precedence
if (mayFirstCheckBox->isChecked()) {
const QDate mayFirst(calendar->yearShown(), 5, 1);
QTextCharFormat mayFirstFormat;
mayFirstFormat.setForeground(Qt::red);
calendar->setDateTextFormat(mayFirst, mayFirstFormat);
}
}
void Window::createPreviewGroupBox()
{
previewGroupBox = new QGroupBox(tr("Preview"));
calendar = new QCalendarWidget;
calendar->setMinimumDate(QDate(1900, 1, 1));
calendar->setMaximumDate(QDate(3000, 1, 1));
calendar->setGridVisible(true);
connect(calendar, SIGNAL(currentPageChanged(int,int)),
this, SLOT(reformatCalendarPage()));
previewLayout = new QGridLayout;
previewLayout->addWidget(calendar, 0, 0, Qt::AlignCenter);
previewGroupBox->setLayout(previewLayout);
}
void Window::createGeneralOptionsGroupBox()
{
generalOptionsGroupBox = new QGroupBox(tr("General Options"));
localeCombo = new QComboBox;
int curLocaleIndex = -1;
int index = 0;
for (int _lang = QLocale::C; _lang <= QLocale::LastLanguage; ++_lang) {
QLocale::Language lang = static_cast<QLocale::Language>(_lang);
QList<QLocale::Country> countries = QLocale::countriesForLanguage(lang);
for (int i = 0; i < countries.count(); ++i) {
QLocale::Country country = countries.at(i);
QString label = QLocale::languageToString(lang);
label += QLatin1Char('/');
label += QLocale::countryToString(country);
QLocale locale(lang, country);
if (this->locale().language() == lang && this->locale().country() == country)
curLocaleIndex = index;
localeCombo->addItem(label, locale);
++index;
}
}
if (curLocaleIndex != -1)
localeCombo->setCurrentIndex(curLocaleIndex);
localeLabel = new QLabel(tr("&Locale"));
localeLabel->setBuddy(localeCombo);
firstDayCombo = new QComboBox;
firstDayCombo->addItem(tr("Sunday"), Qt::Sunday);
firstDayCombo->addItem(tr("Monday"), Qt::Monday);
firstDayCombo->addItem(tr("Tuesday"), Qt::Tuesday);
firstDayCombo->addItem(tr("Wednesday"), Qt::Wednesday);
firstDayCombo->addItem(tr("Thursday"), Qt::Thursday);
firstDayCombo->addItem(tr("Friday"), Qt::Friday);
firstDayCombo->addItem(tr("Saturday"), Qt::Saturday);
firstDayLabel = new QLabel(tr("Wee&k starts on:"));
firstDayLabel->setBuddy(firstDayCombo);
selectionModeCombo = new QComboBox;
selectionModeCombo->addItem(tr("Single selection"),
QCalendarWidget::SingleSelection);
selectionModeCombo->addItem(tr("None"), QCalendarWidget::NoSelection);
selectionModeLabel = new QLabel(tr("&Selection mode:"));
selectionModeLabel->setBuddy(selectionModeCombo);
gridCheckBox = new QCheckBox(tr("&Grid"));
gridCheckBox->setChecked(calendar->isGridVisible());
navigationCheckBox = new QCheckBox(tr("&Navigation bar"));
navigationCheckBox->setChecked(true);
horizontalHeaderCombo = new QComboBox;
horizontalHeaderCombo->addItem(tr("Single letter day names"),
QCalendarWidget::SingleLetterDayNames);
horizontalHeaderCombo->addItem(tr("Short day names"),
QCalendarWidget::ShortDayNames);
horizontalHeaderCombo->addItem(tr("None"),
QCalendarWidget::NoHorizontalHeader);
horizontalHeaderCombo->setCurrentIndex(1);
horizontalHeaderLabel = new QLabel(tr("&Horizontal header:"));
horizontalHeaderLabel->setBuddy(horizontalHeaderCombo);
verticalHeaderCombo = new QComboBox;
verticalHeaderCombo->addItem(tr("ISO week numbers"),
QCalendarWidget::ISOWeekNumbers);
verticalHeaderCombo->addItem(tr("None"), QCalendarWidget::NoVerticalHeader);
verticalHeaderLabel = new QLabel(tr("&Vertical header:"));
verticalHeaderLabel->setBuddy(verticalHeaderCombo);
connect(localeCombo, SIGNAL(currentIndexChanged(int)),
this, SLOT(localeChanged(int)));
connect(firstDayCombo, SIGNAL(currentIndexChanged(int)),
this, SLOT(firstDayChanged(int)));
connect(selectionModeCombo, SIGNAL(currentIndexChanged(int)),
this, SLOT(selectionModeChanged(int)));
connect(gridCheckBox, SIGNAL(toggled(bool)),
calendar, SLOT(setGridVisible(bool)));
connect(navigationCheckBox, SIGNAL(toggled(bool)),
calendar, SLOT(setNavigationBarVisible(bool)));
connect(horizontalHeaderCombo, SIGNAL(currentIndexChanged(int)),
this, SLOT(horizontalHeaderChanged(int)));
connect(verticalHeaderCombo, SIGNAL(currentIndexChanged(int)),
this, SLOT(verticalHeaderChanged(int)));
QHBoxLayout *checkBoxLayout = new QHBoxLayout;
checkBoxLayout->addWidget(gridCheckBox);
checkBoxLayout->addStretch();
checkBoxLayout->addWidget(navigationCheckBox);
QGridLayout *outerLayout = new QGridLayout;
outerLayout->addWidget(localeLabel, 0, 0);
outerLayout->addWidget(localeCombo, 0, 1);
outerLayout->addWidget(firstDayLabel, 1, 0);
outerLayout->addWidget(firstDayCombo, 1, 1);
outerLayout->addWidget(selectionModeLabel, 2, 0);
outerLayout->addWidget(selectionModeCombo, 2, 1);
outerLayout->addLayout(checkBoxLayout, 3, 0, 1, 2);
outerLayout->addWidget(horizontalHeaderLabel, 4, 0);
outerLayout->addWidget(horizontalHeaderCombo, 4, 1);
outerLayout->addWidget(verticalHeaderLabel, 5, 0);
outerLayout->addWidget(verticalHeaderCombo, 5, 1);
generalOptionsGroupBox->setLayout(outerLayout);
firstDayChanged(firstDayCombo->currentIndex());
selectionModeChanged(selectionModeCombo->currentIndex());
horizontalHeaderChanged(horizontalHeaderCombo->currentIndex());
verticalHeaderChanged(verticalHeaderCombo->currentIndex());
}
void Window::createDatesGroupBox()
{
datesGroupBox = new QGroupBox(tr("Dates"));
minimumDateEdit = new QDateEdit;
minimumDateEdit->setDisplayFormat("MMM d yyyy");
minimumDateEdit->setDateRange(calendar->minimumDate(),
calendar->maximumDate());
minimumDateEdit->setDate(calendar->minimumDate());
minimumDateLabel = new QLabel(tr("&Minimum Date:"));
minimumDateLabel->setBuddy(minimumDateEdit);
currentDateEdit = new QDateEdit;
currentDateEdit->setDisplayFormat("MMM d yyyy");
currentDateEdit->setDate(calendar->selectedDate());
currentDateEdit->setDateRange(calendar->minimumDate(),
calendar->maximumDate());
currentDateLabel = new QLabel(tr("&Current Date:"));
currentDateLabel->setBuddy(currentDateEdit);
maximumDateEdit = new QDateEdit;
maximumDateEdit->setDisplayFormat("MMM d yyyy");
maximumDateEdit->setDateRange(calendar->minimumDate(),
calendar->maximumDate());
maximumDateEdit->setDate(calendar->maximumDate());
maximumDateLabel = new QLabel(tr("Ma&ximum Date:"));
maximumDateLabel->setBuddy(maximumDateEdit);
connect(currentDateEdit, SIGNAL(dateChanged(QDate)),
calendar, SLOT(setSelectedDate(QDate)));
connect(calendar, SIGNAL(selectionChanged()),
this, SLOT(selectedDateChanged()));
connect(minimumDateEdit, SIGNAL(dateChanged(QDate)),
this, SLOT(minimumDateChanged(QDate)));
connect(maximumDateEdit, SIGNAL(dateChanged(QDate)),
this, SLOT(maximumDateChanged(QDate)));
QGridLayout *dateBoxLayout = new QGridLayout;
dateBoxLayout->addWidget(currentDateLabel, 1, 0);
dateBoxLayout->addWidget(currentDateEdit, 1, 1);
dateBoxLayout->addWidget(minimumDateLabel, 0, 0);
dateBoxLayout->addWidget(minimumDateEdit, 0, 1);
dateBoxLayout->addWidget(maximumDateLabel, 2, 0);
dateBoxLayout->addWidget(maximumDateEdit, 2, 1);
dateBoxLayout->setRowStretch(3, 1);
datesGroupBox->setLayout(dateBoxLayout);
}
void Window::createTextFormatsGroupBox()
{
textFormatsGroupBox = new QGroupBox(tr("Text Formats"));
weekdayColorCombo = createColorComboBox();
weekdayColorCombo->setCurrentIndex(
weekdayColorCombo->findText(tr("Black")));
weekdayColorLabel = new QLabel(tr("&Weekday color:"));
weekdayColorLabel->setBuddy(weekdayColorCombo);
weekendColorCombo = createColorComboBox();
weekendColorCombo->setCurrentIndex(
weekendColorCombo->findText(tr("Red")));
weekendColorLabel = new QLabel(tr("Week&end color:"));
weekendColorLabel->setBuddy(weekendColorCombo);
headerTextFormatCombo = new QComboBox;
headerTextFormatCombo->addItem(tr("Bold"));
headerTextFormatCombo->addItem(tr("Italic"));
headerTextFormatCombo->addItem(tr("Plain"));
headerTextFormatLabel = new QLabel(tr("&Header text:"));
headerTextFormatLabel->setBuddy(headerTextFormatCombo);
firstFridayCheckBox = new QCheckBox(tr("&First Friday in blue"));
mayFirstCheckBox = new QCheckBox(tr("May &1 in red"));
connect(weekdayColorCombo, SIGNAL(currentIndexChanged(int)),
this, SLOT(weekdayFormatChanged()));
connect(weekendColorCombo, SIGNAL(currentIndexChanged(int)),
this, SLOT(weekendFormatChanged()));
connect(headerTextFormatCombo, SIGNAL(currentIndexChanged(QString)),
this, SLOT(reformatHeaders()));
connect(firstFridayCheckBox, SIGNAL(toggled(bool)),
this, SLOT(reformatCalendarPage()));
connect(mayFirstCheckBox, SIGNAL(toggled(bool)),
this, SLOT(reformatCalendarPage()));
QHBoxLayout *checkBoxLayout = new QHBoxLayout;
checkBoxLayout->addWidget(firstFridayCheckBox);
checkBoxLayout->addStretch();
checkBoxLayout->addWidget(mayFirstCheckBox);
QGridLayout *outerLayout = new QGridLayout;
outerLayout->addWidget(weekdayColorLabel, 0, 0);
outerLayout->addWidget(weekdayColorCombo, 0, 1);
outerLayout->addWidget(weekendColorLabel, 1, 0);
outerLayout->addWidget(weekendColorCombo, 1, 1);
outerLayout->addWidget(headerTextFormatLabel, 2, 0);
outerLayout->addWidget(headerTextFormatCombo, 2, 1);
outerLayout->addLayout(checkBoxLayout, 3, 0, 1, 2);
textFormatsGroupBox->setLayout(outerLayout);
weekdayFormatChanged();
weekendFormatChanged();
reformatHeaders();
reformatCalendarPage();
}
QComboBox *Window::createColorComboBox()
{
QComboBox *comboBox = new QComboBox;
comboBox->addItem(tr("Red"), Qt::red);
comboBox->addItem(tr("Blue"), Qt::blue);
comboBox->addItem(tr("Black"), Qt::black);
comboBox->addItem(tr("Magenta"), Qt::magenta);
return comboBox;
}
//#include "moc_calwidget.cpp"

121
Tests/QtAutomoc/calwidget.h Normal file
View File

@ -0,0 +1,121 @@
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
** the names of its contributors may be used to endorse or promote
** products derived from this software without specific prior written
** permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** 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."
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef WINDOW_H
#define WINDOW_H
#include <QWidget>
class QCalendarWidget;
class QCheckBox;
class QComboBox;
class QDate;
class QDateEdit;
class QGridLayout;
class QGroupBox;
class QLabel;
class Window : public QWidget
{
Q_OBJECT
public:
Window();
private slots:
void localeChanged(int index);
void firstDayChanged(int index);
void selectionModeChanged(int index);
void horizontalHeaderChanged(int index);
void verticalHeaderChanged(int index);
void selectedDateChanged();
void minimumDateChanged(const QDate &date);
void maximumDateChanged(const QDate &date);
void weekdayFormatChanged();
void weekendFormatChanged();
void reformatHeaders();
void reformatCalendarPage();
private:
void createPreviewGroupBox();
void createGeneralOptionsGroupBox();
void createDatesGroupBox();
void createTextFormatsGroupBox();
QComboBox *createColorComboBox();
QGroupBox *previewGroupBox;
QGridLayout *previewLayout;
QCalendarWidget *calendar;
QGroupBox *generalOptionsGroupBox;
QLabel *localeLabel;
QLabel *firstDayLabel;
QLabel *selectionModeLabel;
QLabel *horizontalHeaderLabel;
QLabel *verticalHeaderLabel;
QComboBox *localeCombo;
QComboBox *firstDayCombo;
QComboBox *selectionModeCombo;
QCheckBox *gridCheckBox;
QCheckBox *navigationCheckBox;
QComboBox *horizontalHeaderCombo;
QComboBox *verticalHeaderCombo;
QGroupBox *datesGroupBox;
QLabel *currentDateLabel;
QLabel *minimumDateLabel;
QLabel *maximumDateLabel;
QDateEdit *currentDateEdit;
QDateEdit *minimumDateEdit;
QDateEdit *maximumDateEdit;
QGroupBox *textFormatsGroupBox;
QLabel *weekdayColorLabel;
QLabel *weekendColorLabel;
QLabel *headerTextFormatLabel;
QComboBox *weekdayColorCombo;
QComboBox *weekendColorCombo;
QComboBox *headerTextFormatCombo;
QCheckBox *firstFridayCheckBox;
QCheckBox *mayFirstCheckBox;
};
#endif

View File

@ -0,0 +1,153 @@
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
** the names of its contributors may be used to endorse or promote
** products derived from this software without specific prior written
** permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** 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."
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QtGui>
#include "codeeditor.h"
CodeEditor::CodeEditor(QWidget *parent) : QPlainTextEdit(parent)
{
lineNumberArea = new LineNumberArea(this);
connect(this, SIGNAL(blockCountChanged(int)), this, SLOT(updateLineNumberAreaWidth(int)));
connect(this, SIGNAL(updateRequest(QRect,int)), this, SLOT(updateLineNumberArea(QRect,int)));
connect(this, SIGNAL(cursorPositionChanged()), this, SLOT(highlightCurrentLine()));
updateLineNumberAreaWidth(0);
highlightCurrentLine();
}
int CodeEditor::lineNumberAreaWidth()
{
int digits = 1;
int max = qMax(1, blockCount());
while (max >= 10) {
max /= 10;
++digits;
}
int space = 3 + fontMetrics().width(QLatin1Char('9')) * digits;
return space;
}
void CodeEditor::updateLineNumberAreaWidth(int /* newBlockCount */)
{
setViewportMargins(lineNumberAreaWidth(), 0, 0, 0);
}
void CodeEditor::updateLineNumberArea(const QRect &rect, int dy)
{
if (dy)
lineNumberArea->scroll(0, dy);
else
lineNumberArea->update(0, rect.y(), lineNumberArea->width(), rect.height());
if (rect.contains(viewport()->rect()))
updateLineNumberAreaWidth(0);
}
void CodeEditor::resizeEvent(QResizeEvent *e)
{
QPlainTextEdit::resizeEvent(e);
QRect cr = contentsRect();
lineNumberArea->setGeometry(QRect(cr.left(), cr.top(), lineNumberAreaWidth(), cr.height()));
}
void CodeEditor::highlightCurrentLine()
{
QList<QTextEdit::ExtraSelection> extraSelections;
if (!isReadOnly()) {
QTextEdit::ExtraSelection selection;
QColor lineColor = QColor(Qt::yellow).lighter(160);
selection.format.setBackground(lineColor);
selection.format.setProperty(QTextFormat::FullWidthSelection, true);
selection.cursor = textCursor();
selection.cursor.clearSelection();
extraSelections.append(selection);
}
setExtraSelections(extraSelections);
}
void CodeEditor::lineNumberAreaPaintEvent(QPaintEvent *event)
{
QPainter painter(lineNumberArea);
painter.fillRect(event->rect(), Qt::lightGray);
QTextBlock block = firstVisibleBlock();
int blockNumber = block.blockNumber();
int top = (int) blockBoundingGeometry(block).translated(contentOffset()).top();
int bottom = top + (int) blockBoundingRect(block).height();
while (block.isValid() && top <= event->rect().bottom()) {
if (block.isVisible() && bottom >= event->rect().top()) {
QString number = QString::number(blockNumber + 1);
painter.setPen(Qt::black);
painter.drawText(0, top, lineNumberArea->width(), fontMetrics().height(),
Qt::AlignRight, number);
}
block = block.next();
top = bottom;
bottom = top + (int) blockBoundingRect(block).height();
++blockNumber;
}
}
#include "codeeditor.moc"

View File

@ -0,0 +1,99 @@
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
** the names of its contributors may be used to endorse or promote
** products derived from this software without specific prior written
** permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** 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."
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef CODEEDITOR_H
#define CODEEDITOR_H
#include <QPlainTextEdit>
#include <QObject>
class QPaintEvent;
class QResizeEvent;
class QSize;
class QWidget;
class LineNumberArea;
class CodeEditor : public QPlainTextEdit
{
Q_OBJECT
public:
CodeEditor(QWidget *parent = 0);
void lineNumberAreaPaintEvent(QPaintEvent *event);
int lineNumberAreaWidth();
protected:
void resizeEvent(QResizeEvent *event);
private slots:
void updateLineNumberAreaWidth(int newBlockCount);
void highlightCurrentLine();
void updateLineNumberArea(const QRect &, int);
private:
QWidget *lineNumberArea;
};
class LineNumberArea : public QWidget
{
public:
LineNumberArea(CodeEditor *editor) : QWidget(editor) {
codeEditor = editor;
}
QSize sizeHint() const {
return QSize(codeEditor->lineNumberAreaWidth(), 0);
}
protected:
void paintEvent(QPaintEvent *event) {
codeEditor->lineNumberAreaPaintEvent(event);
}
private:
CodeEditor *codeEditor;
};
#endif

58
Tests/QtAutomoc/main.cpp Normal file
View File

@ -0,0 +1,58 @@
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
** the names of its contributors may be used to endorse or promote
** products derived from this software without specific prior written
** permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** 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."
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QtGui>
#include "codeeditor.h"
#include "calwidget.h"
int main(int argv, char **args)
{
QApplication app(argv, args);
CodeEditor editor;
editor.setWindowTitle(QObject::tr("Code Editor Example"));
editor.show();
Window w;
w.show();
return app.exec();
}