Qt4 TreeView – Items Filtering

August 30, 2008 | Filed Under Qt4 | 1 Comment

In a few words, I’ve a QTreeView that displays folder items. I Need to filter items, showing empty folders.

QSortFilterProxyModel: For hierarchical models, the filter is applied recursively to all children. If a parent item doesn’t match the filter, none of its children will be shown.

Using QSortFilterProxyModel the result is that the filter is applied on the foldes, so we’ve something like a root only filter. The solution is simple.. Inherits QSortFilterProxyModel and…

class QfTreeProxyModel : public QSortFilterProxyModel {
 public:
  QfTreeProxyModel (QObject *parent = 0)
     : QSortFilterProxyModel(parent)
  {
      setFilterCaseSensitivity(Qt::CaseInsensitive);
  }

 protected:
  bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const
  {
    QModelIndex idx = sourceModel()->index(source_row, 0, source_parent);
    if (sourceModel()->hasChildren(idx))
      return(true);
    return(QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent));
  }
};
Qt4 Filtered TreeView

Qt4 Filtered TreeView

Here you can find the example source code: http://th30z.netsons.org/wp-content/uploads/qfilteredtreeview.cpp

Qt4 Mac SearchBox Wrapper

August 17, 2008 | Filed Under Mac OS X, Qt4 | No Comments

Do you want to use Mac OS X SearchBox in your Qt Application? Ok, pick up your XCode or your preferred code editor and we’ll start to write a Qt Wrapper for Carbon HISearchField.

The Header File will be something like this, with two signals textChanged(const QString&) that will be used to “Filter on the Fly” it will be raised when the user type something, findNext() will be raised when user press Return Button.

#if defined(Q_WS_MAC) && !defined(_QF_MAC_SEARCHBOX_H_)
#define _QF_MAC_SEARCHBOX_H_

// Qt4 Headers
#include <QWidget>

// Mac OS X - Carbon Headers
#include <Carbon/Carbon.h>

class QfMacSearchBox : public QWidget {
    Q_OBJECT

    public:
        QfMacSearchBox (QWidget *parent = 0);
        ~QfMacSearchBox();

        // Methods
        void raiseTextChanged (void);
        void raiseFindNext (void);

        QSize sizeHint (void) const;

        // GET Properties
        QString text (void) const;

    signals:
        void textChanged (const QString& text);
        void findNext (void);

    public slots:
        void setText (const QString& text);
        void clear (void);

    private:
        CFStringRef searchFieldText;
        HIViewRef searchField;
};

#endif // Q_WS_MAC && !_QF_MAC_SEARCHBOX_H_

And now the Class Implementation. I’ve internally managed the clear button, so you haven’t a clear signals but a textChanged(const QString&) signal with an empty string.

// Qt4 Headers
#include <QVarLengthArray>
#include <QMenu>

// SearchBox Headers
#include "searchbox_mac.h"

// =======================================
//  MacSearchBox: PRIVATE FILE Methods
// =======================================
static QString toQString(CFStringRef str) {
    if(!str)
        return QString();

    CFIndex length = CFStringGetLength(str);
    const UniChar *chars = CFStringGetCharactersPtr(str);
    if (chars)
        return QString(reinterpret_cast<const QChar *>(chars), length);

    QVarLengthArray<UniChar> buffer(length);
    CFStringGetCharacters(str, CFRangeMake(0, length), buffer.data());
    return QString(reinterpret_cast<const QChar *>(buffer.constData()), length);
}

static OSStatus SearchFieldEventHandler(EventHandlerCallRef handlerCallRef,
                                        EventRef event, void *userData)
{
    QfMacSearchBox *searchBox = (QfMacSearchBox *) userData;
    OSType eventClass = GetEventClass(event);
    UInt32 eventKind = GetEventKind(event);

    if (eventClass == kEventClassSearchField) {
        switch (eventKind) {
            case kEventSearchFieldCancelClicked:
                searchBox->clear();
                break;
            case kEventSearchFieldSearchClicked:
                searchBox->raiseFindNext();
                break;
            default:
                break;
        }
    } else if (eventClass == kEventClassTextField) {
        switch (eventKind) {
            case kEventTextDidChange:
                searchBox->raiseTextChanged();
                break;
            case kEventTextAccepted:
                searchBox->raiseFindNext();
                break;
            default:
                break;
        }
    }

    return(eventNotHandledErr);
}

// =======================================
//  MacSearchBox: PUBLIC Constructors/Destructors
// =======================================
QfMacSearchBox::QfMacSearchBox (QWidget *parent)
    : QWidget(parent)
{
    // Set Widget Properties
    //setFocusPolicy(Qt::StrongFocus);
    setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));

    // Create a native search field and pass its window id to QWidget::create.
    searchFieldText = CFStringCreateWithCString(0,
                                     (const char *) tr("Search").toAscii(), 0);
    HISearchFieldCreate(NULL, kHISearchFieldAttributesSearchIcon |
                              kHISearchFieldAttributesCancel,
                        NULL, searchFieldText, &searchField);
    create(reinterpret_cast<WId>(searchField));

    // Subscribe Events
    EventTypeSpec mySFieldEvents[] = {
                     { kEventClassSearchField, kEventSearchFieldCancelClicked },
                     { kEventClassTextField, kEventTextDidChange },
                     { kEventClassTextField, kEventTextAccepted }
                 };

    HIViewInstallEventHandler(searchField, SearchFieldEventHandler,
                              GetEventTypeCount(mySFieldEvents), mySFieldEvents,
                              (void *) this, NULL);

    // Use a Qt menu for the search field menu.
    QMenu *searchMenu = new QMenu(this);

    QAction *indexAction = searchMenu->addAction(tr("Index Search"));
    indexAction->setCheckable(true);
    indexAction->setChecked(true);

    QAction *fulltextAction = searchMenu->addAction(tr("Full Text Search"));
    fulltextAction->setCheckable(true);

    QActionGroup *searchActionGroup = new QActionGroup(this);
    searchActionGroup->addAction(indexAction);
    searchActionGroup->addAction(fulltextAction);
    searchActionGroup->setExclusive(true);

    MenuRef macSearchMenu = searchMenu->macMenu(0);
    HISearchFieldSetSearchMenu(searchField, macSearchMenu);
}

QfMacSearchBox::~QfMacSearchBox() {
    CFRelease(searchField);
    CFRelease(searchFieldText);
}

// =======================================
//  MacSearchBox: PUBLIC Methods
// =======================================
void QfMacSearchBox::raiseTextChanged (void) {
    emit textChanged(text());
}

void QfMacSearchBox::raiseFindNext (void) {
    emit findNext();
}

QSize QfMacSearchBox::sizeHint (void) const {
    HIRect optimalBounds;
    EventRef event;

    CreateEvent(0, kEventClassControl, kEventControlGetOptimalBounds,
                GetCurrentEventTime(), kEventAttributeUserEvent, &event);

    SendEventToEventTargetWithOptions(event,
                                HIObjectGetEventTarget(HIObjectRef(winId())),
                                kEventTargetDontPropagate);

    GetEventParameter(event, kEventParamControlOptimalBounds, typeHIRect,
                      0, sizeof(HIRect), 0, &optimalBounds);

    ReleaseEvent(event);
    return QSize(optimalBounds.size.width + 200, optimalBounds.size.height);
}

// =======================================
//  MacSearchBox: PUBLIC GET Properties
// =======================================
QString QfMacSearchBox::text (void) const {
    CFStringRef cfString = HIViewCopyText(searchField);
    QString text = toQString(cfString);
    CFRelease(cfString);
    return(text);
}

// =======================================
//  MacSearchBox: PUBLIC SET Properties
// =======================================
void QfMacSearchBox::setText (const QString& text) {
    CFRelease(searchFieldText);

    searchFieldText = CFStringCreateWithCString(0,
                          (const char *) text.toAscii(), 0);
    HIViewSetText(searchField, searchFieldText);

    emit textChanged(text);
}

void QfMacSearchBox::clear (void) {
    setText(QString());
}

That’s all folks.

Qt4 Mac Dock Icon Click

August 11, 2008 | Filed Under Mac OS X, Qt4 | 6 Comments

When you click the “close button” of an application’s window, on Mac OS X the window will be hidden but the application continue running. When you click on the Dock Icon, the application’s window will be showed. This is the default behaviour for Mac Apps but Qt Apps doesn’t the same. So, how we could implement this behaviour?

#ifndef _APPLICATION_H_
#define _APPLICATION_H_

// Qt4 Headers
include <QApplication>
include <QWidget>

// Carbon Headers
#ifdef Q_WS_MAC
    #include <Carbon/Carbon.h>
#endif

class Application : public QApplication {
    Q_OBJECT

    public:
        Application (int& argc, char **argv);

         QWidget *mainWindow (void) const;

    private:
         QWidget *m_mainWindow;

#ifdef Q_WS_MAC
    AEEventHandlerUPP m_appleEventProcessorUPP;
#endif
};

#endif // !_APPLICATION_H_

Here, we’ve implemented an Application class that Inherits from QApplication. This class contains a reference to the App’s Main Window.

#ifdef Q_WS_MAC
static OSStatus appleEventProcessor(const AppleEvent *ae,
                                    AppleEvent *event,
                                    long handlerRefCon)
{
    Application *app = (Application *) handlerRefCon;

     OSType aeID = typeWildCard;
     OSType aeClass = typeWildCard;

     AEGetAttributePtr(ae, keyEventClassAttr, typeType, 0,
                       &aeClass, sizeof(aeClass), 0);
     AEGetAttributePtr(ae, keyEventIDAttr, typeType, 0,
                       &aeID, sizeof(aeID), 0);

     if (aeClass == kCoreEventClass) {
          if (aeID == kAEReopenApplication) {
               app->mainWindow()->show();
          }
          return noErr;
    }

    return eventNotHandledErr;
}
#endif

Application::Application (int& argc, char **argv)
    : QApplication(argc, argv)
{
    // Don't Quit the App on Window Close
    setQuitOnLastWindowClosed(false);

    // Initialize Main Window
    m_mainWindow = new QLabel("Test Main Window");

#ifdef Q_WS_MAC
    // Install Reopen Application Event (Dock Clicked)
    m_appleEventProcessorUPP = AEEventHandlerUPP(appleEventProcessor);
    AEInstallEventHandler(kCoreEventClass, kAEReopenApplication,
                          m_appleEventProcessorUPP, (long) this, true);
#endif
}

QWidget *Application::mainWindow (void) const {
    return(m_mainWindow);
}

Thats all folks! Run the app, Click on close button and then click on the dock icon to see the result.

Just for Fun – Qt4 DeviantArt

August 11, 2008 | Filed Under Qt4 | No Comments

Just for Fun, I’ve developed a “Ten Minutes App” to demonstrate how to retrieve images from DeviantArt Feed. (This will be a Quartica Plugin).

You can find the source here: deviantart-sample.tar.bz2

Qt4 “Freedesktop” MIME Type

August 11, 2008 | Filed Under Qt4 | No Comments

A couple of weeks ago, i’ve released at Qt Apps a Qt Component called QFreeDesktopMime that is a simple class for determining the MIME type of files using FreeDesktop Specification.

How to use this class? it’s really simple.

Example 1: Get Information about specified MIME Type

QFreeDesktopMime mime;
QString description = mime.description("application/epub+zip");
QString expandedAcronym = mime.expandedAcronym("text/x-xslfo");
QString acronym = mime.acronym("text/x-xslfo");

Example 2: Extract MIME Type and information from File Name (Results based on File Extension)

QFreeDesktopMime mime;
QString mimeType = mime.fromFileName("test.png");
QString mimeDescription = mime.description();

Example 3: Extract MIME Type and information from File (Data)

QFreeDesktopMime mime;
QString mimeType = mime.fromFile("/home/oz/myUnknownFile");
QString mimeDescription = mime.description();

If fromFile() method doesn’t find the matching data it tries to use fromFileName() method to get the MIME Type. In all cases if file’s MIME Type wasn’t found it returns an empty QString.

Qt4 Image Transfers Viewer

August 9, 2008 | Filed Under Qt4 | No Comments

Today a new Qt4 Effect developed for Quartica File Transfers View. The main idea is to remove the unuseful progressbar from Downloading Images and replace it with something more intuitive.

Quartica Image Transfers Viewer

Quartica Image Transfers Viewer

In this way, you can see the full image and the current completed part. And now a Very Low quality video that demonstrate how it works (please, wait 7 seconds before going away).

Qt4 ThumbViewer

August 6, 2008 | Filed Under Qt4 | No Comments

It’s only a Work in Progress class, but this screenshot will be the Album Viewer Widget of Quartica.
All the images are behind a shadow effect and so it looks all darker. What do you think about it?

Qt4 ThumbViewer

Qt4 Thumbnail Viewer

And here, after a couple of days the second version of Qt4 Thumbnail Viewer.

Thumbnail Viewer 2nd Version

Qt4 Thumbnail Viewer 2nd Version