So... das wird länger dauern ^^ Ich bin mir unsicher ob ich meinen Code bereits commiten soll. Hier mal grob meine Änderungen:
interface.h:
Code: Alles auswählen
namespace Dedupe
{
class File;
namespace GUI
{
namespace MainAction
{
/**
* The following Tokens will be send by the GetAction()-method
* and describe the action the user has selected
*/
enum MainAction
{
Append, ///< Append button (at list) was pressed
Remove, ///< Remove item (at list) was pressed
Index, ///< Index button was pressed
Manage, ///< Manage button was pressed
Delete, ///< Delete items which are selected for deletion
Edit, ///< Delete items which are selected for deletion
Hide, ///< Hide window
Show, ///< Restore hidden window
Quit ///< Exit to operating system
};
}
/**
* This class describes the interface to the main window.
*/
class Main
{
public:
/**
* Refresh the main window - add the given File to the list
* \param file reference to the new file
*/
virtual void AppendFile( const Dedupe::FileInfo & file ) = 0;
/**
* Refresh the main window - remove the given File to the list
*/
virtual void RemoveFile( const Dedupe::FileInfo & file ) = 0;
public:
/**
* Waits for user interaction
*/
virtual int exec() = 0;
Main( int argc, char *argv[] ) { /* Handle Parameters */ }
virtual ~Main() {}
protected:
/**
* Get several files from the user
*/
virtual const std::vector<Dedupe::FileInfo>& GetFiles() = 0;
void OnAppend()
{
std::cout << "OnAppend" << std::endl;
const std::vector<Dedupe::FileInfo>& files = GetFiles();
std::cout << "adding to user interface:" << std::endl;
for( int i = 0; i < files.size(); i++ )
{
std::cout << "\t" << files[i].GetPath() << std::endl;
AppendFile( files[i] );
}
}
void OnRemove()
{
std::cout << "OnRemove" << std::endl;
}
void OnIndex()
{
std::cout << "OnIndex" << std::endl;
}
void OnManage()
{
std::cout << "OnManage" << std::endl;
}
void OnDelete()
{
std::cout << "OnDelete" << std::endl;
}
void OnEdit()
{
std::cout << "OnEdit" << std::endl;
}
void OnHide()
{
std::cout << "Hiding window" << std::endl;
}
void OnShow()
{
std::cout << "Showing window" << std::endl;
}
void OnQuit()
{
std::cout << "Shutting down" << std::endl;
}
};
}
}
Die Main-Instanz erhält nun argc und argv als Parameter. Ich dachte das könnte später mal nützlich sein und ich bau es gleich ein.
Weiters hab ich die Parameter von AppendFile()/RemoveFile() von File auf FileInfo geändert. Ich hab nirgends eine Implementierung von File gefunden?! Außerdem glaube ich nicht, dass man für die Oberfläche die Daten in der Datei braucht.
Zu den Framework-unabhängigen Callbacks. Hier ein Beispiel wie ich mir das vorgestellt habe:
Code: Alles auswählen
void OnAppend()
{
const std::vector<Dedupe::FileInfo>& files = GetFiles();
for( int i = 0; i < files.size(); i++ )
AppendFile( files[i] );
}
OnAppend() bekommt über die rein virtuelle Methode GetFiles() jene Dateien, die der Benutzer zum Einfügen ausgewählt hat. Danach werden sie über die rein virtuelle Methode AppendFiles() eingefügt. Vorteil: Diese Implementierung ist komplett unabhängig vom darunterliegenden Framework. Nachrteil: Unser Interface ist jetzt kein echtes Interface mehr :/ Die Implementierung hab ich momentan direkt im Header, sollte aber natürlich in eine Quelldatei ausgelagtert werden. Ich wollte jetzt aber nicht auch noch an CMake rumpfuschen.
Über exec() wird nun die Oberfläche "gestartet". NCurses wartet an dieser Stelle auf Events und behandelt diese. Qt übergibt an den Event-Handler und wartet auf dessen Informationen. Das main sieht im Idealfall so aus:
Code: Alles auswählen
int main( int argc, char *argv[] )
{
Dedupe::GUI::NCursesMain gui( argc, argv );
return gui.exec();
}
Für Qt muss davor noch ein QApplication-Objekt erstellt werden.
Je nachdem welcher Event ausgelöst wird, wird ein Interface-Callback wie OnAppend() aufgerufen. Dabei wird das interne Event-Handling abgekapselt. Es gibt ja innerhalb von Qt schon 2 Methoden Events zu behandeln.
Hier ein Beispiel wie die 1. Methode abgekapselt wird:
Code: Alles auswählen
void QtMain::closeEvent( QCloseEvent *event )
{
OnQuit();
QWidget::closeEvent( event );
}
Wir das Fenster geschlossen (und somit das Programm beendet) wird von Qt die Methode closeEvent() aufgerufen. Darin wird auf das Interface zurückgegriffen und das restliche Event-Handling an die Basisklasse übergeben.
2. Methode über Signals und Slots:
Code: Alles auswählen
connect( Append, SIGNAL( clicked() ),
this, SLOT( handleButtonClicked() ) );
// ...
void QtMain::handleButtonClicked()
{
if( sender() == Index )
OnIndex();
else if( sender() == Append )
OnAppend();
// ...
}
Alle Button-Events werden in der handleButtonClicked()-Methode verarbeitet. In dieser Methode muss nur noch der Auslöser ( = sender() ) festgestellt werden und die entsprechende Interface-Methode aufgerufen werden.
Ich würde gerne die Benutzeroberflächen so schnell wie möglich mit dem Kernel verbinden. Auch um die Entwicklungsumgebung besser nutzen zu können. Ich verwende den Qt-Creator. Mit ihm lassen sich CMake-Programme problemlos bearbeiten und kompilieren. Das zu kompilierende Programm selbst muss Qt nicht zwingend verwenden! Es reicht die höchste CMakeLists.txt mit dem Creator zu öffnen.
Nun habe ich die Qt-Oberfläche soweit, dass sie über das Interface auf Events reagiert. Ich hab jetzt einen Button über den man Dateien auswählen kann, die dann in die (grafische) Liste eingefügt werden. Dabei bekomme ich einen Segmentation Fault. Ich bin mir aber ziemlich sicher, dass der nicht aus meinem Code kommt:
Code: Alles auswählen
==6813== Process terminating with default action of signal 11 (SIGSEGV)
==6813== Access not within mapped region at address 0x1A
==6813== at 0x66C14F8: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::string const&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.16)
==6813== by 0x4098CC: boost::filesystem3::path::path(boost::filesystem3::path const&) (path.hpp:127)
==6813== by 0x4E6C090: Dedupe::FileInfo::GetPath() const (fileinfo.cpp:98)
==6813== by 0x409BA6: Dedupe::GUI::Main::OnAppend() (interface.h:79)
==6813== by 0x40965B: Dedupe::GUI::QtMain::handleButtonClicked() (implementation.cpp:130)
// ...
Das ist die vorhin bereits gezeigte Stelle, hier nochmal etwas ausführlicher da ich vorhin die Debug-Ausgaben weggelassen habe:
Code: Alles auswählen
void OnAppend()
{
std::cout << "OnAppend" << std::endl;
const std::vector<Dedupe::FileInfo>& files = GetFiles();
std::cout << "adding to user interface:" << std::endl;
for( int i = 0; i < files.size(); i++ )
{
std::cout << "\t" << files[i].GetPath() << std::endl;
AppendFile( files[i] );
}
}
Die Datei hat von Qt sicher einen gültigen Pfad bekommen, ich hab ihn mir zuvor ausgeben lassen. Was mir schon mal komisch vorkam:
fileinfo.cpp, erster Konstruktor:
Code: Alles auswählen
Dedupe::FileInfo::FileInfo( Dedupe::FilePath PathToFile ):
Path(""), Size( 0 ), DateChanged( 0 ), Existing( false ),
Type( TNotAvailable ), Hash( 0 ), Keep( false ),
StateOfFile( FileStatusNotSet ), FileSearchErrorMessage( "" )
{
Warum bekommt Path einen leeren String, obwohl doch PathToFile übergeben wird? Verstehe ich etwas falsch? Daran liegts aber nicht, hab schon versucht das zu ändern.
Und das letzte Thema, womit ich mich wahrscheinlich an fat-lobyte richte. Ich bekomme jetzt beim Kompilieren 865 Warnings... Ich weiß es sind nur Warnings, aber trotzdem stört mich die Zahl etwas ^^ Die sind natürlich fast alle nicht von Dedupe selbst. Ich bekomme aber Meldungen wie:
Code: Alles auswählen
/usr/include/qt4/QtGui/qstyleoption.h: At global scope:
/usr/include/qt4/QtGui/qstyleoption.h:747:20: warning: base class ‘class QStyleOptionComplex’ has a non-virtual destructor [-Weffc++]
/usr/include/qt4/QtGui/qstyleoption.h: In copy constructor ‘QStyleOptionQ3ListView::QStyleOptionQ3ListView(const QStyleOptionQ3ListView&)’:
/usr/include/qt4/QtGui/qstyleoption.h:762:5: warning: ‘QStyleOptionQ3ListView::items’ should be initialized in the member initialization list [-Weffc++]
/usr/include/qt4/QtGui/qstyleoption.h:762:5: warning: ‘QStyleOptionQ3ListView::viewportPalette’ should be initialized in the member initialization list [-Weffc++]
/usr/include/qt4/QtGui/qstyleoption.h:762:5: warning: ‘QStyleOptionQ3ListView::viewportBGRole’ should be initialized in the member initialization list [-Weffc++]
/usr/include/qt4/QtGui/qstyleoption.h:762:5: warning: ‘QStyleOptionQ3ListView::sortColumn’ should be initialized in the member initialization list [-Weffc++]
/usr/include/qt4/QtGui/qstyleoption.h:762:5: warning: ‘QStyleOptionQ3ListView::itemMargin’ should be initialized in the member initialization list [-Weffc++]
/usr/include/qt4/QtGui/qstyleoption.h:762:5: warning: ‘QStyleOptionQ3ListView::treeStepSize’ should be initialized in the member initialization list [-Weffc++]
/usr/include/qt4/QtGui/qstyleoption.h:762:5: warning: ‘QStyleOptionQ3ListView::rootIsDecorated’ should be initialized in the member initialization list [-Weffc++]
Aha. Ich bekomme Fehlermeldungen über den Qt-Quellcode?! Wäre es schlimm den -Weffc++-Flag rauszunehmen? Oder kann man das anders verhindern?
Das wars für heute ^^