Detecting missing resources in QT Stylesheets - qt

I am using QCSS stylesheets in QT to skin several buttons with images from the QT resource system:
QFrame#DialogButtonTitle_SaveAsNew
{
background-image: url(images:DialogButtonTitle_SaveAsNew.png);
}
This works great, but I would really like to write a warning to our logs if the image file referenced from the CSS could not be found (and the button is thus naked). Any way to catch such errors?

I believe you can do it like this:
Read about the QAbstractFileEngine and QAbstractFileEngineHandler classes.
Extend Qt's own implementation, QFSFileEngine. I believe it also handles the ":" namespace.
Reimplement the QAbstractFileEngine::open() method.
Register your engine using a custom QAbstractFileEngineHandler. The create() method should check the file name to see if it is being read from a resource file.
Haven't tested, but I think it should work. Code:
bool MyEngine::open(QIODevice::OpenMode mode)
{
bool r = QFSFileEngine::open(mode);
if (!r) {
qWarning() << "Failed to open" << fileName();
}
return r;
}
QAbstractFileEngine *MyEngineHandler::create(const QString &fileName) const
{
return fileName.startsWith("images:") ? new MyEngine(fileName) : 0;
}
Edit.
This will not work. The resource file system, “:”, is handled by a private file engine called QResourceFileEngine, not by QFSFileEngine.

Based on #andref answer, I came up with this, which works for me (TM):
class LoggingEngineHandler : public QAbstractFileEngineHandler
{
public:
LoggingEngineHandler()
: QAbstractFileEngineHandler()
, m_lookUpInProgress(false)
, m_lookUpPaths(QRegExp("^(images|meshes|app|sounds):"))
{
// empty
}
QAbstractFileEngine* create(const QString &fileName) const override
{
if (!fileName.contains(m_lookUpPaths))
return 0;
if (m_lookUpInProgress)
return 0;
m_lookUpInProgress = true;
QFileInfo info = QFileInfo(fileName);
m_lookUpInProgress = false;
if (!info.exists())
{
assert(!Utilities::isRunByUser("designer"));
LOG_WARN("Required resource file does not exist: %1%", QUtil_s(fileName));
}
return 0;
}
protected:
mutable bool m_lookUpInProgress;
QRegExp m_lookUpPaths;
};

It's possible that Qt will call one of their message functions when something like this happens (although I don't know for sure). If it does, you could install a message handler function and append some or all of the messages to your log file. There is some information about doing so in the documentation for qInstallMsgHandler.

Related

How to use directory operations in C++Builder?

I am stuck in creating a directory with C++Builder. If you check this here and here, I find examples for my case, but when I try to use them, none of them work for me! For example, the following code for creating a directory, where the edSourcePath->Text value has been defined.
Unfortunately the documentation is not complete.
try
{
/* Create directory to specified path */
TDirectory::CreateDirectory(edSourcePath->Text);
}
catch (...)
{
/* Catch the possible exceptions */
MessageDlg("Incorrect path", mtError, TMsgDlgButtons() << mbOK, NULL);
return;
}
The error message says TDirectory is not a class or namespace.
Another question is, how can I pass the source path and directory name by CreateDirectory(edSourcePath->Text)?
What you are seeing is a compile-time error, not a runtime error. The compiler cannot find the definition of the TDirectory class. You need to #include the header file that TDirectory is defined in, eg:
#include <System.IOUtils.hpp> // <-- add this!
try
{
/* Create directory to specified path */
TDirectory::CreateDirectory(edSourcePath->Text);
// or, if either DELPHIHEADER_NO_IMPLICIT_NAMESPACE_USE or
// NO_USING_NAMESPACE_SYSTEM_IOUTILS is defined, you need
// to use the fully qualified name instead:
//
// System::Ioutils::TDirectory::CreateDirectory(edSourcePath->Text);
}
catch (const Exception &e)
{
/* Catch the possible exceptions */
MessageDlg("Incorrect path.\n" + e.Message, mtError, TMsgDlgButtons() << mbOK, NULL);
return;
}
Note, however, that TDirectory::CreateDirectory() throws an exception ONLY if the input String is not a valid formatted path. It DOES NOT throw an exception if the actual directory creation fails. In fact, there is no way to detect that condition with TDirectory::CreateDirectory() itself, you would have to check with TDirectory::Exists() afterwards:
#include <System.IOUtils.hpp>
try
{
/* Create directory to specified path */
String path = edSourcePath->Text;
TDirectory::CreateDirectory(path);
if (!TDirectory::Exists(path))
throw Exception("Error creating directory");
}
catch (const Exception &e)
{
/* Catch the possible exceptions */
MessageDlg(e.Message, mtError, TMsgDlgButtons() << mbOK, NULL);
return;
}
Otherwise, TDirectory::CreateDirectory() is just a validating wrapper for System::Sysutils::ForceDirectories(), which has a bool return value. So, you could just call that function directly instead:
#include <System.SysUtils.hpp>
/* Create directory to specified path */
if (!ForceDirectories(edSourcePath->Text)) // or: System::Sysutils::ForceDirectories(...), if needed
{
MessageDlg("Error creating directory", mtError, TMsgDlgButtons() << mbOK, NULL);
return;
}

log4cxx -- is it possible to configure a custom appender with custom arguments from a config file?

I need to write a custom appender in log4cxx. This answer describes how to do it. In Java, in log4j, it is possible for a custom appender to devise custom parameters. I add a property and a getter and setter:
private int myParameter = 0;
public void setMyParameter(int p) { myParameter = p; }
public int getMyParameter() { return myParameter; }
Then I can use myParameter in configuration file, and the framework somehow knows how to configure my appender with it.
Question: does log4cxx have a similar capability? For me it is enough if I get a map map<string, string> with properties.
Ok, figured out the answer myself. You need to override member function setOption. It will get called a number of times: once per each read option. You then override function activateOptions and its get called after all options have been processed. It can be used as a trigger to initialize the appender with the read parameters.
Not as convenient as mapping to getters/setters, but it gets the job done:
class CustomAppender : public AppenderSkeleton
{
int _myParameter = 0;
void initialize(int myParameter);
// ...
public:
void setOption(LogString const& option, LogString const& value) override
{
if (option == "MyParameter") try
{
_myParameter = boost::lexical_cast<int>(value);
}
catch (boost::bad_lexical_cast const&) {
// go with default
}
}
void activateOptions(helpers::Pool &) override
{
initialize(_myParameter);
}
};

Using a Filter in SharePoint HTTPModule to intercept binary data returns corrupt data

I have researched the following extensively on both Stack Overflow and Google without any luck. Bear with me while I explain what I am trying to achieve and the problem I am encountering.
I am developing a SharePoint 2007 application that adds a basic watermark to any image (jpg, gif, png) that is requested by the browser. It doesn't matter if the image resides in a document library or the server's file system as part of the '12 hive'. (This is a simplification of the solution that is being build, I don't want to bore you with the irrelevant details).
As this will need to work with any image served up, independent of the 3rd party solutions that may be running on SharePoint, the only solution I see is to write an HTTPModule, hook the Module's Filter, read the image data from the stream and replace it with the watermarked version of the image. It is not possible to use SharePoint's event receivers for this and SharePoint's 'Server side File handlers' do not cover all scenarios for delivering these kind of files to the browser.
Although intercepting and modifying text based content using a filter works just fine, when the filter contains binary data the custom filter's Write method receives corrupt data. The byte[] is correct until a 00 is encountered in the source file, so it sounds like either an encoding problem (of binary data??) or HTTPModule filters do not allow binary data, which I find hard to believe.
The weird thing is that when the binary file (image) is read by SharePoint from the server's file system then it is passed through my filter properly. However, the moment the binary file is read from a SharePoint Document Library the data is corrupted.
To confirm this I have carried out the following tests:
Requesting a 1.3MB TXT file from both the server's file system and SharePoint document library works fine. When read from the file system it arrives in one big chunk. When read from the Document library it arrives in 32KB sized chunks.
Requesting a 300KB Binary Image that resides on the server's file system is processed fine by the filter. However requesting the same file from a document library returns corrupt data.
Requesting a 3KB GIF Image from a document library returns corrupt data. The first 10 bytes are fine after which data becomes corrupt (byte 10 is a 0 in the source file)
When the custom filter is not enabled then the requested files are always returned successfully to the browser.
The entry point in our custom filter is the Write method. The data in the buffer that is passed to this method is already corrupt.
I understand that multiple HTTPModules are chained. I have tried placing my custom module both at the beginning as well as the end of the list of Modules in the web.config file, without any luck
The relevant code in the HTTPModule for hooking up the filter is as follows:
void context_BeginRequest(object sender, EventArgs e)
{
HttpContext.Current.Response.Filter = new ResponseFilter(HttpContext.Current.Response.Filter);
}
The implementation of the ResponseFilter Class is as follows. Note that it doesn't actually do anything at the moment other than writing the source data back to the output stream.
public class ResponseFilter : Stream
{
private MemoryStream internalStream = new MemoryStream();
private Stream responseStream;
public ResponseFilter(Stream outputStream)
{
responseStream = outputStream;
}
public override void Flush()
{
responseStream.Flush();
}
public override void Write(byte[] buffer, int offset, int count)
{
internalStream.Write(buffer, offset, count);
responseStream.Write(buffer, offset, count);
}
public override void Close()
{
responseStream.Close();
}
public override bool CanRead
{
get { return true; }
}
public override bool CanWrite
{
get { return true; }
}
public override bool CanSeek
{
get { return true; }
}
public override long Length
{
get { return internalStream.Length; }
}
public override long Position
{
get { return internalStream.Position; }
set { internalStream.Position = value; }
}
public override int Read(byte[] buffer, int offset, int count)
{
return internalStream.Read(buffer, offset, count);
}
public override long Seek(long offset, SeekOrigin direction)
{
return internalStream.Seek(offset, direction);
}
public override void SetLength(long length)
{
internalStream.SetLength(length);
}
}
This class is far from perfect, but the problem is that the moment the Write method is hit the data in the buffer is already corrupt. The rest of the class doesn't matter at the moment.
This is an old question and you may have resolved this issue. If it's still open you might consider testing to see if turning off post-cache substitution resolves the corruption issue. See ASP.Net Response Filter Clashing with SharePoint 2010 Publishing Site Defaults for more details. It's a long shot but maybe worth the time to test.

Flex Console - How to use it?

I'm checking "Flex Console" --> here that looks really interesting.
It seems easy to use and light to integrate. But how? I've been looking around for some info about it but haven't been successful. I found this post but I don't understand how it is used...
If anyone have any idea on how to use it or have any recommendation about any other app that would do the same (save clear flex logs with filters and stuff) I'd be really appreciated.
Regards,
BS_C3
Flex Console has moved to a new location: http://code.google.com/p/flex-console/
In a nutshell, you create a MiniDebugTarget in your project and start logging using the Logging API.
import mx.logging.*;
import mx.logging.targets.*;
public class MyApp {
static private logger:ILogger = Log.getLogger("sample.MyApp");
public function MyApp() {
super();
// Add the MinuDebugTarget to channel
// all log messages to LocalConnection
// You only need to do this once!
var target:MiniDebugTarget = new MiniDebugTarget();
target.filters = ["*"];
target.includeDate = true;
target.includeTime = true;
target.includeCategory = true;
target.includeLevel = true;
Log.addTarget(target);
}
public function foo(bar:String):void {
logger.debug("foo({0})", bar);
try {
// do something
..
} catch(e:Error) {
logger.error("Error: ", e.message);
throw e;
}
}
}
Check out the Help page at the new site.

Blocking a Qt application during downloading a short file

I'm writing an application using Qt4.
I need to download a very short text file from a given http address.
The file is short and is needed for my app to be able to continue, so I would like to make sure the download is blocking (or will timeout after a few seconds if the file in not found/not available).
I wanted to use QHttp::get(), but this is a non-blocking method.
I thought I could use a thread : my app would start it, and wait for it to finish. The thread would handle the download and quit when the file is downloaded or after a timeout.
But I cannot make it work :
class JSHttpGetterThread : public QThread
{
Q_OBJECT
public:
JSHttpGetterThread(QObject* pParent = NULL);
~JSHttpGetterThread();
virtual void run()
{
m_pHttp = new QHttp(this);
connect(m_pHttp, SIGNAL(requestFinished(int, bool)), this, SLOT(onRequestFinished(int, bool)));
m_pHttp->setHost("127.0.0.1");
m_pHttp->get("Foo.txt", &m_GetBuffer);
exec();
}
const QString& getDownloadedFileContent() const
{
return m_DownloadedFileContent;
}
private:
QHttp* m_pHttp;
QBuffer m_GetBuffer;
QString m_DownloadedFileContent;
private slots:
void onRequestFinished(int Id, bool Error)
{
m_DownloadedFileContent = "";
m_DownloadedFileContent.append(m_GetBuffer.buffer());
}
};
In the method creating the thread to initiate the download, here is what I'm doing :
JSHttpGetterThread* pGetter = new JSHttpGetterThread(this);
pGetter->start();
pGetter->wait();
But that doesn't work and my app keeps waiting. It looks lit the slot 'onRequestFinished' is never called.
Any idea ?
Is there a better way to do what I'm trying to do ?
Instead of using a thread you can just go into a loop which calls processEvents:
while (notFinished) {
qApp->processEvents(QEventLoop::WaitForMore | QEventLoop::ExcludeUserInput);
}
Where notFinished is a flag which can be set from the onRequestFinished slot.
The ExcludeUserInput will ensure that GUI related events are ignored while waiting.
A little late but:
Do not use these wait loops, the correct way is to use the done() signal from QHttp.
The requestFinished signal from what I have seen is just for when your application has finished the request, the data may still be on its way down.
You do not need a new thread, just setup the qhttp:
httpGetFile= new QHttp();
connect(httpGetFile, SIGNAL(done(bool)), this, SLOT(processHttpGetFile(bool)));
Also do not forget to flush the file in processHttpGetFile as it might not all be on the disk.
you have to call QThread::quit() or exit() if you are done - otherwise your thread will run forever...
I chose to implement David's solution, which seemed to be the easiest.
However, I had handle a few more things :
I had to adapt the QEventLoop enum values for Qt4.3.3 (the version I'm using);
I had to track the request Id, to make sure to exit the while loop when the download request is finished, and not when another request is finished;
I added a timeout, to make sure to exit the while loop if there is any problem.
Here is the result as (more or less) pseudo-code :
class BlockingDownloader : public QObject
{
Q_OBJECT
public:
BlockingDownloaderBlockingDownloader()
{
m_pHttp = new QHttp(this);
connect(m_pHttp, SIGNAL(requestFinished(int, bool)), this, SLOT(onRequestFinished(int, bool)));
}
~BlockingDownloader()
{
delete m_pHttp;
}
QString getFileContent()
{
m_pHttp->setHost("www.xxx.com");
m_DownloadId = m_pHttp->get("/myfile.txt", &m_GetBuffer);
QTimer::singleShot(m_TimeOutTime, this, SLOT(onTimeOut()));
while (!m_FileIsDownloaded)
{
qApp->processEvents(QEventLoop::WaitForMoreEvents | QEventLoop::ExcludeUserInputEvents);
}
return m_DownloadedFileContent;
}
private slots:
void BlockingDownloader::onRequestFinished(int Id, bool Error)
{
if (Id == m_DownloadId)
{
m_DownloadedFileContent = "";
m_DownloadedFileContent.append(m_GetBuffer.buffer());
m_FileIsDownloaded = true;
}
}
void BlockingDownloader::onTimeOut()
{
m_FileIsDownloaded = true;
}
private:
QHttp* m_pHttp;
bool m_FileIsDownloaded;
QBuffer m_GetBuffer;
QString m_DownloadedFileContent;
int m_DownloadId;
};
I used QNetworkAccsessManager for same necessity. Because this class managing connections RFC base (6 proccess same time) and non-blocking.
http://qt-project.org/doc/qt-4.8/qnetworkaccessmanager.html
How about giving the GUI some amount of time to wait on the thread and then give up.
Something like:
JSHttpGetterThread* pGetter = new JSHttpGetterThread(this);
pGetter->start();
pGetter->wait(10000); //give the thread 10 seconds to download
Or...
Why does the GUI thread have to wait for the "downloader thread" at all? When the app fires up create the downloader thread, connect the finished() signal to some other object, start the downloader thread, and return. When the thread has finished, it will signal the other object which can resume your process.

Resources