PDA

View Full Version : Help with qt plugin



usva.techdev
6th April 2013, 03:12
Hi,

I'm implementing teh tutorial qt-project.org/doc/qt-5.0/qtdoc/gettingstartedqml.html I have implemented correctly everything about QML and GUI works ok. At the moment of using the plugin I'm able to generate both libFileDIalog.a and FileDialog.dll.

However when i integrate the plugin into the qml text editor things doesn't compile as it is supposed to do. This is my .pro file



# Add more folders to ship with the application, here
folder_01.source = qml/TextEditor
folder_01.target = qml
DEPLOYMENTFOLDERS = folder_01

# Additional import path used to resolve QML modules in Creator's code model
QML_IMPORT_PATH =

symbian:TARGET.UID3 = 0xE6CF9A7F

# Smart Installer package's UID
# This UID is from the protected range and therefore the package will
# fail to install if self-signed. By default qmake uses the unprotected
# range value if unprotected UID is defined for the application and
# 0x2002CCCF value if protected UID is given to the application
#symbian:DEPLOYMENT.installer_header = 0x2002CCCF

# Allow network access on Symbian
symbian:TARGET.CAPABILITY += NetworkServices

# If your application uses the Qt Mobility libraries, uncomment the following
# lines and add the respective components to the MOBILITY variable.
# CONFIG += mobility
# MOBILITY +=

# Speed up launching on MeeGo/Harmattan when using applauncherd daemon
# CONFIG += qdeclarative-boostable

# Add dependency to Symbian components
# CONFIG += qt-components

# The .cpp file which was generated for your project. Feel free to hack it.
SOURCES += main.cpp

INCLUDEPATH += "D:/DSUsers/uidv3469/Tutoriales/Qt/QML/TextEditor/qml/TextEditor/Library"
LIBS += "D:/DSUsers/uidv3469/Tutoriales/Qt/QML/TextEditor/qml/TextEditor/Library/FileDialog.dll"
HEADERS += "D:/DSUsers/uidv3469/Tutoriales/Qt/QML/TextEditor/qml/TextEditor/Library/dialogPlugin.h" \
"D:/DSUsers/uidv3469/Tutoriales/Qt/QML/TextEditor/qml/TextEditor/Library/directory.h" \
"D:/DSUsers/uidv3469/Tutoriales/Qt/QML/TextEditor/qml/TextEditor/Library/file.h"

# Please do not modify the following two lines. Required for deployment.
include(qmlapplicationviewer/qmlapplicationviewer.pri)
qtcAddDeployment()



it marks me this errors:



debug/moc_dialogPlugin.o:moc_dialogPlugin.cpp:(.rdata$_Z TV12DialogPlugin[vtable for DialogPlugin]+0x38): undefined reference to `DialogPlugin::registerTypes(char const*)'
debug/moc_dialogPlugin.o:moc_dialogPlugin.cpp:(.rdata$_Z TV12DialogPlugin[vtable for DialogPlugin]+0x50): undefined reference to `non-virtual thunk to DialogPlugin::registerTypes(char const*)'
debug/moc_directory.o:D:\DSUsers\uidv3469\Tutoriales\Qt\ QML\TextEditor-build-desktop-Qt_4_8_1_for_Desktop_-_MinGW__Qt_SDK__Debug/debug/moc_directory.cpp:74: undefined reference to `Directory::saveFile()'
debug/moc_directory.o:D:\DSUsers\uidv3469\Tutoriales\Qt\ QML\TextEditor-build-desktop-Qt_4_8_1_for_Desktop_-_MinGW__Qt_SDK__Debug/debug/moc_directory.cpp:75: undefined reference to `Directory::loadFile()'
debug/moc_directory.o:D:\DSUsers\uidv3469\Tutoriales\Qt\ QML\TextEditor-build-desktop-Qt_4_8_1_for_Desktop_-_MinGW__Qt_SDK__Debug/debug/moc_directory.cpp:122: undefined reference to `Directory::filesCount() const'
debug/moc_directory.o:D:\DSUsers\uidv3469\Tutoriales\Qt\ QML\TextEditor-build-desktop-Qt_4_8_1_for_Desktop_-_MinGW__Qt_SDK__Debug/debug/moc_directory.cpp:123: undefined reference to `Directory::files()'
debug/moc_directory.o:D:\DSUsers\uidv3469\Tutoriales\Qt\ QML\TextEditor-build-desktop-Qt_4_8_1_for_Desktop_-_MinGW__Qt_SDK__Debug/debug/moc_directory.cpp:124: undefined reference to `Directory::filename() const'
debug/moc_directory.o:D:\DSUsers\uidv3469\Tutoriales\Qt\ QML\TextEditor-build-desktop-Qt_4_8_1_for_Desktop_-_MinGW__Qt_SDK__Debug/debug/moc_directory.cpp:125: undefined reference to `Directory::fileContent() const'
debug/moc_directory.o:D:\DSUsers\uidv3469\Tutoriales\Qt\ QML\TextEditor-build-desktop-Qt_4_8_1_for_Desktop_-_MinGW__Qt_SDK__Debug/debug/moc_directory.cpp:131: undefined reference to `Directory::setFilename(QString const&)'
debug/moc_directory.o:D:\DSUsers\uidv3469\Tutoriales\Qt\ QML\TextEditor-build-desktop-Qt_4_8_1_for_Desktop_-_MinGW__Qt_SDK__Debug/debug/moc_directory.cpp:132: undefined reference to `Directory::setFileContent(QString const&)'
debug/moc_file.o:D:\DSUsers\uidv3469\Tutoriales\Qt\QML\T extEditor-build-desktop-Qt_4_8_1_for_Desktop_-_MinGW__Qt_SDK__Debug/debug/moc_file.cpp:102: undefined reference to `File::name() const'
debug/moc_file.o:D:\DSUsers\uidv3469\Tutoriales\Qt\QML\T extEditor-build-desktop-Qt_4_8_1_for_Desktop_-_MinGW__Qt_SDK__Debug/debug/moc_file.cpp:108: undefined reference to `File::setName(QString const&)'
collect2: ld returned 1 exit status
mingw32-make.exe[1]: *** [debug/TextEditor.exe] Error 1
mingw32-make.exe: *** [debug] Error 2
18:25:11: The process "D:\TOOL\QtSDK\mingw\bin\mingw32-make.exe" exited with code 2.
Error while building project TextEditor (target: Desktop)
When executing build step 'Make'


I looked at the libraries generated qith a text editor, and apparently the references to the methods are inside the library so I would say the reference exist, but for some reason it is no being find.

Could anybody shed some light on why this thing is not finding the reference to mentioned functions?


Best regards,

Ulises Vega

wysota
6th April 2013, 09:38
Is this .pro file for the plugin or for the application? What is the "Directory" class? Where is it defined? If it is defined in a plugin then you can't access it directly from the application. If you want to access it from the application, you need to link your application against the library (which stops being a plugin at this moment). If you do that, remember to export all the symbols from the library that you want to be accessible in code using that library.

usva.techdev
9th April 2013, 00:58
Is this .pro file for the plugin or for the application? What is the "Directory" class? Where is it defined? If it is defined in a plugin then you can't access it directly from the application. If you want to access it from the application, you need to link your application against the library (which stops being a plugin at this moment). If you do that, remember to export all the symbols from the library that you want to be accessible in code using that library.


Hello wysota thanks for your prompt reply.
1.- THe pro file that i posted is for the applicationn
2.- The pro file for my plugin is:



TEMPLATE = lib
CONFIG += qt plugin
QT += declarative

DESTDIR += ../plugins
OBJECTS_DIR = tmp
MOC_DIR = tmp

TARGET = FileDialog

HEADERS += directory.h \
file.h \
dialogPlugin.h

SOURCES += directory.cpp \
file.cpp \
dialogPlugin.cpp



I'm not sure wether I'm developing a qt plugin or a shared library. But I'm sure I'm trying to implement this modulehttp://qt-project.org/doc/qt-5.0/qtdoc/gettingstartedqml.html

3.- Directory is a class defined in the plugin This is the code for the headers of the plugin:

the source code for dialogPlugin.h is:


#ifndef DIALOGPLUGIN_H
#define DIALOGPLUGIN_H

#include <QtDeclarative/QDeclarativeExtensionPlugin>

class DialogPlugin : public QDeclarativeExtensionPlugin
{
Q_OBJECT

public:
//registerTypes is inherited from QDeclarativeExtensionPlugin
void registerTypes(const char *uri);

};


Source code for DialogPlugin.cpp (This is the only class that exports something)


#include "dialogPlugin.h"
#include "directory.h"
#include "file.h"
#include <QtDeclarative/qdeclarative.h>

void DialogPlugin::registerTypes(const char *uri)
{
//register the class Directory into QML as a "Directory" element version 1.0
qmlRegisterType<Directory>(uri, 1, 0, "Directory");
qmlRegisterType<File>(uri,1,0,"File");
}

//FileDialog is the plugin name (same as the TARGET in the project file) and DialogPlugin is the plugin classs
Q_EXPORT_PLUGIN2(FileDialog, DialogPlugin);



Source code in Directory.h, this module create some variables accessible form QML via Q_PROPERTY


#ifndef DIRECTORY_H
#define DIRECTORY_H

#include "file.h"

#include <QDir>
#include <QStringList>
#include <QTextStream>
#include <QDeclarativeListProperty>
#include <QObject>

class Directory : public QObject {

Q_OBJECT

//number of files in the directory
Q_PROPERTY(int filesCount READ filesCount)

//list property containing file names as QString
Q_PROPERTY(QDeclarativeListProperty<File> files READ files CONSTANT )

//file name of the text file to read/write
Q_PROPERTY(QString filename READ filename WRITE setFilename NOTIFY filenameChanged)

//text content of the file
Q_PROPERTY(QString fileContent READ fileContent WRITE setFileContent NOTIFY fileContentChanged)

public:
Directory(QObject *parent = 0);

//properties' read functions
int filesCount() const;
QString filename() const;
QString fileContent() const;
QDeclarativeListProperty<File> files();

//properties' write functions
void setFilename(const QString &str);
void setFileContent(const QString &str);

//accessible from QML
Q_INVOKABLE void saveFile();
Q_INVOKABLE void loadFile();

signals:
void directoryChanged();
void filenameChanged();
void fileContentChanged();

private:
QDir m_dir;
QStringList m_dirFiles;
File currentFile;
QString m_saveDir;
QStringList m_filterList;

//contains the file data in QString format
QString m_fileContent;

//Registered to QML in a plugin. Accessible from QML as a property of Directory
QList<File *> m_fileList;

//refresh content of the directory
void refresh();
};


Source code for directory.cpp, only normal C++ source code without exports.


#include "directory.h"
#include <QDebug>

/*
Directory constructor

Initialize the saves directory and creates the file list
*/
Directory::Directory(QObject *parent) : QObject(parent)
{
m_dir.cd( QDir::currentPath() );

//go to the saved directory. if not found, create save directory
m_saveDir = "saves";
if ( m_dir.cd(m_saveDir) == 0 ) {
m_dir.mkdir(m_saveDir);
m_dir.cd(m_saveDir);
}
m_filterList << "*.txt";
refresh();
}

/*
Directory::filesNumber
Return the number of Files
*/
int Directory::filesCount() const
{
return m_fileList.size();
}

/*
Function called to append data onto list property
*/
void appendFiles(QDeclarativeListProperty<File> * property, File * file)
{
Q_UNUSED(property);
Q_UNUSED(file);
//Do nothing. can't add to a directory using this method
}

/*
Function called to retrieve file in the list using an index
*/
File* fileAt(QDeclarativeListProperty<File> * property, int index)
{
return static_cast< QList<File *> *>(property->data)->at(index);
}

/*
Returns the number of files in the list
*/
int filesSize(QDeclarativeListProperty<File> * property)
{
return static_cast< QList<File *> *>(property->data)->size();
}

/*
Function called to empty the list property contents
*/
void clearFilesPtr(QDeclarativeListProperty<File> *property)
{
return static_cast< QList<File *> *>(property->data)->clear();
}

/*
Returns the list of files as a QDeclarativeListProperty.
*/
QDeclarativeListProperty<File> Directory::files()
{
refresh();
return QDeclarativeListProperty<File>( this, &m_fileList, &appendFiles, &filesSize, &fileAt, &clearFilesPtr );
}

/*
Return the name of the currently selected file
*/
QString Directory::filename() const
{
return currentFile.name();
}

/*
Return the file's content as a string.
*/
QString Directory::fileContent() const
{
return m_fileContent;
}

/*
Set the file name of the current file
*/
void Directory::setFilename(const QString &str)
{
if( str != currentFile.name() ) {
currentFile.setName(str);
emit filenameChanged();
}
}

/*
Set the content of the file as a string
*/
void Directory::setFileContent(const QString &str)
{
if(str != m_fileContent){
m_fileContent = str;
emit fileContentChanged();
}
}

/*
Called from QML to save the file using the filename and file content.
Saving makes sure that the file has a .txt extension.
*/
void Directory::saveFile()
{
if(currentFile.name().size() == 0){
qWarning()<< "Empty filename. no save";
return;
}
QString extendedName = currentFile.name();
if(!currentFile.name().endsWith(".txt")){
extendedName.append(".txt");
}
QFile file( m_dir.filePath(extendedName) );
if ( file.open(QFile::WriteOnly | QFile::Truncate) ) {
QTextStream outStream(&file);
outStream << m_fileContent;
}
file.close();
refresh();
emit directoryChanged();
}

/*
Load the contents of a file.
Only loads files with a .txt extension
*/
void Directory::loadFile()
{
m_fileContent.clear();
QString extendedName = currentFile.name();
if( !currentFile.name().endsWith(".txt") ) {
extendedName.append(".txt");
}

QFile file( m_dir.filePath(extendedName) );
if ( file.open(QFile::ReadOnly ) ) {
QTextStream inStream(&file);

QString line;
do {
line = inStream.read(75);
m_fileContent.append(line);
} while ( !line.isNull() ) ;
}
file.close();
}

/*
Reloads the content of the files list. This is to ensure that the newly
created files are added onto the list.
*/
void Directory::refresh()
{
m_dirFiles = m_dir.entryList(m_filterList,QDir::Files,QDir::Nam e);
m_fileList.clear();

File * file;
for(int i = 0; i < m_dirFiles.size() ; i ++) {
file = new File();

if( m_dirFiles.at(i).endsWith(".txt") ) {
QString name = m_dirFiles.at(i);
file->setName( name.remove(".txt",Qt::CaseSensitive) );
}
else {
file->setName(m_dirFiles.at(i));
}
m_fileList.append(file);
}
}




source code in file.h


#include <QString>
#include <QObject>

class File : public QObject{

Q_OBJECT

Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)

public:
File(QObject *parent = 0);

QString name() const;
void setName(const QString &str);

signals:
void nameChanged();

private:
QString m_name;
};


source code for file.cpp


#include "file.h"

File::File(QObject *parent) : QObject(parent)
{
m_name = "";
}

QString File::name() const{
return m_name;
}
void File::setName(const QString &str){
if(str != m_name){
m_name = str;
emit nameChanged();
}
}


As you could see I'm trying to expand QML functionality through plugins as the examples "getting started", previously quoted proposes.

Thanks for your help, I appreciate it a lot.

Ulises Vega