Στο προηγούμενο tutorial φτιάξαμε μια γραφική εφαρμογή, το BookAdmin, για να διαχειρίζεστε τη συλλογή των βιβλίων σας χρησιμοποιώντας μια βάση δεδομένων MySQL. Δεν ήταν κάτι ιδιαίτερο, βέβαια, και η αλήθεια είναι ότι θα έπρεπε ίσως να συνεχίζαμε την ανάπτυξή της (βάζοντας π.χ. φίλτρα για τις εγγραφές). Ωστόσο, πολλοί αναγνώστες του “LF” μας ζήτησαν με ευγενικό τρόπο (μας δωροδόκησαν καλά!) να τους δώσουμε έναν τρόπο αρχειοθέτησης των άρθρων του περιοδικού για όλα τα μέχρι σήμερα τεύχη. Οπότε σκεφτήκαμε: “τι καλύτερο από το να γράψουμε ένα μικρό tutorial γι’ αυτό βασιζόμενοι σε ότι κάναμε στο BookAdmin;” Έτσι, αυτή τη φορά, θα φτιάξουμε μια τέτοια εφαρμογούλα για να τηρείτε το “αρχείο” σας, αλλά και για να δείτε πως φτιάχνεται κάτι τέτοιο στην πράξη. Τέτοιο …making of ούτε στο Holywood δεν θα βρείτε! 😛 Σημείωση: μπορείτε να κατεβάσετε όλον τον κώδικα του άρθρου από εδώ.

Το σχέδιο έχει ως εξής. Η εφαρμογή, ας την βαφτίσουμε ArtAdmin, θα πρέπει να έχει ένα γραφικό περιβάλλον αντίστοιχο του BookAdmin, δηλαδή με πεδία για προβολή και αναζήτηση κάποιων εγγραφών (δηλαδή άρθρων) και ένα TableView σε ξεχωριστή καρτέλα για να βλέπετε όλα τα άρθρα μαζί. Συνεχίζοντας με αυταπάρνηση την παράδοση που θέλει κάθε προγραμματιστή …τεμπέλη, θα βασιστούμε στη φόρμα του BookAdmin αλλάζοντας ελαφρώς την πρώτη καρτέλα της για να φτιάξουμε το ολοκαίνουριο ArticlesAdmin – φασόν δηλαδή 🙂 Αυτή τη φορά, όμως θα προσθέσουμε και μερικά νέα κόλπα…

Προφανώς δεν μπορούμε να ζητήσουμε από εσάς να κάτσετε να γράψετε και να εισάγετε σε μια βάση δεδομένων ένα προς ένα όλα τα άρθρα όλων των προηγούμενων τευχών, γι’ αυτό το πρόγραμμα θα πρέπει να έχει τη δυνατότητα να διαβάζει αρχεία CSV (Comma Separated Values), δηλαδή text αρχεία στα οποία οι στήλες ξεχωρίζουν από μία κόμμα (ή κάποιο άλλο σύμβολο όπως θα δούμε!). Το σκεπτικό μας είναι ότι στο DVD κάθε νέου τεύχους θα βάζουμε και ένα αρχείο κειμένου με τα περιεχόμενα του, το οποίο θα “φορτώνετε” στο ArtAdmin για να ενημερώσετε τη MySQL βάση δεδομένων σας (σ.σ. δυστυχώς αυτή η ιδέα δεν συνεχίστηκε στα επόμενα τεύχη του Linux Format). Μέχρι εδώ όλα καλά. Τι πληροφορίες θα πρέπει να έχει όμως ένα τέτοιο αρχείο κειμένου για να είναι χρήσιμο στο ArtAdmin; Σκεφτήκαμε τα εξής:

1. Τον πλήρη τίτλο του.
2. Τον συντάκτη
3. Τον αριθμό του τεύχους, π.χ. 1.
4. Το δίμηνο, π.χ. Ιανουαρίου-Φεβρουαρίου.
5. Είδος, π.χ. Newsdesk, Θέμα, Αφιέρωμα, Tutorial.
6. Την σελίδα όπου ξεκινά.
7. Μια μικρή περίληψη.

Εντάξει, καταλήξαμε για την μορφή των αρχείων μας – θα έχουν επτά στήλες. Υπάρχει όμως ένα πρόβλημα: Επειδή οι τίτλοι και οι περιλήψεις περιέχουν κόμμα, δεν μπορούμε να χρησιμοποιήσουμε ακριβώς CSV αρχεία, γιατί το πρόγραμμα θα μπερδεύεται. Αντίθετα, θα προτιμήσουμε ένα αστεράκι (*) ως διαχωριστικό των στηλών.

Τι χρειάζεστε
Για άλλη μια φορά σας θυμίζω ότι βασιζόμαστε στην εργαλειοθήκη Qt 4.x οπότε, ανάλογα με τη διανομή σας, θα πρέπει να έχετε ήδη εγκαταστήσει τα πακέτα ανάπτυξης της Qt4 (δείτε τεύχος 17 για αναλυτικές πληροφορίες εγκατάστασης για κάθε διανομή!). Επιπλέον, επειδή θα δουλέψουμε ξανά με βάσης δεδομένων, θα πρέπει να εγκαταστήσετε και το πακέτο libqt4-sql στο Debian/Ubuntu (ή το qt4-database-plugin-mysql-lib στο PCLinuxOS). Κατά τ’ άλλα, θα αρκεστούμε και πάλι στo Qt Designer και σε ένα κειμενογράφο. Προσωπικά, προτιμώ τα KWrite/Gedit, άλλοι επιμένουν στο Vim. Κανείς δεν ξέρει γιατί. 🙂

Ανακύκλωση στο GUI!
Για το GUI του ArtAdmin, θα βασιστούμε στη δουλειά που κάναμε στο bookAdmin, αλλάζοντας αρκετά την πρώτη καρτέλα. Τρέξτε λοιπόν το QtDesigner και φορτώστε το bookadminform.ui (ο κώδικας του είναι στο DVD!). Αμέσως μετά αποθηκεύστε το σε ένα νέο φάκελο με το όνομα artadminform.ui.

Τώρα πρέπει να κάνουμε τις αλλαγές στην πρώτη καρτέλα. Πρώτα στα εύκολα. Κάντε δεξί κλικ στον τίτλο “Καταχώρηση βιβλίου”, επιλέξτε Change Rich Text και γράψτε “Κατάλογος Linux Format”. Από κάτω πρέπει να υπάρχουν οι ετικέτες: “Τίτλος” και “Συγγραφέας” με δύο αντίστοιχα πεδία. Αλλάξτε με τον ίδιο τρόπο την ετικέτα “Συγγραφέας” σε “Συντάκτης” (ή ένδοξος συντάκτης ή πολυχρονεμένος συντάκτης ή …). Το objectName του αντίστοιχου πεδίου από κάτω θέλει επίσης αλλαγή. Δεξί κλικ πάνω του > Change ObjectName και από authorLE κάντε το editorLE. Αν θέλετε, αλλάξτε και την ετικέτα “Τίτλος” σε “Τίτλος άρθρου” για να είναι πιο ξεκάθαρο. Επιπλέον, διαγράψτε το Horizontal Spacer που βρίσκεται εκεί, για να μεγεθυνθούν τα πεδία.


Ξεκινάμε από τη φόρμα του bookAdmin και σιγά-σιγά την τροποποιούμε.

Από κάτω, θα πρέπει να υπάρχουν δύο ετικέτες με πεδία, το ISBΝ και Σελίδες. Αλλάξτε τις ετικέτες σε Τεύχος και Μήνας, αντίστοιχα, και τα objectNames των πεδίων σε issueLE και monthLE, αντίστοιχα. Από κάτω θα δείτε την ετικέτα Τιμή με το αντίστοιχο πεδίο. Αλλάξτε τους ονόματα σε “Είδος Άρθρου” και typeLE, αντιστοιχα.

Τώρα θα κάνουμε ένα μαγικό. Επειδή χρειαζόμαστε ένα ακόμα πεδίο απ’ όσα είχαμε φτιάξει την προηγούμενη φορά, πατήστε το Shift και κάντε κλικ και στην ετικέτα και στο πεδίο για το είδος του άρθρου που μόλις αλλάξαμε. Με πατήμένο το Shift, κάντε δεξί κλικ και Copy. Μετά πηγαίνετε στο κενό ανάμεσα στο πεδίο και το Spacer και κάντε Paste. Θα εμφανιστεί ένα αντίγραφο του ζεύγους ετικέτας-πεδίου. Αν δεν είναι σε layout, αλλά είναι ξεχωριστά, κάντε κλικ και στα δύο πατώντας το Shift και μετά δεξί κλικ και Lay out > Layout Vertically. Τώρα τα δύο στοιχεία θα συμπεριφέρονται ως ένα. Κατόπιν, αν χρειάζεται σύρετε αυτό το στοιχείο ώστε να έρθει δεξιά του “Ειδος Αρθρου”. Όπως κάναμε πριν, αλλάξτε τα ονόματα στην ετικέτα και το πεδίο σε “Σελίδες” και pagesLE, αντίστοιχα.

Από κάτω, θα βλέπετε το πεδίο “Βαθμολογία” που μας είναι άχρηστο. Στη θέση του θα βάλουμε την περιγραφή του άρθρου. Γι’ αυτό αλλάξτε την ετικέτα σε “Περίληψη” και από το μενού του QtDesigner σύρετε από κάτω ένα TextBrowser, που θα το ονομάσετε summaryLE. Επίσηςαφαιρέστε το Horizontal Spacer.

Τελειώσαμε σχεδόν – το μόνο που μένει είναι να προσθέσουμε ένα πεδίο LineEdit αριστερά του κουμπιού “Εισαγωγή” που βρίσκεται στο κάτω μέρος. Απλά κάντε Copy ένα πεδίο από τα προηγούμενα και μετά Paste κάπου στην φόρμα. Έπειτα σύρετέ το έτσι ώστε να έρθει στα αριστερά του κουμπιού Εισαγωγή. Αλλάξτε του το όνομα σε searchLE. Επιπλέον, επειδή το ArtAdmin προορίζεται κυρίως για προβολή στοιχείων και όχι για τόσο καταχώρηση, αλλάξτε το όνομα του κουμπιού σε “Αναζήτηση” και το objectName του από enterBt του σε searchBt.

Τέλος, σύρετε από το μενού του QtDesigner ένα νέο QPushButton, δίπλα από το Αναζήτηση. Ονομάστε το αντικείμενο clearBt και στην ετικέτα του γράψτε Καθαρισμός. Τελειώσαμε! Το αποτέλεσμα θα πρέπει να είναι σαν της εικόνας @@. Αν θέλετε να φαίνεται ακριβώς έτσι, αφαιρέστε τελειώς το Horizontal Spacer και προσθέστε μια περιγραφή πάνω από το πεδίο αναζήτησης…


Ακολουθώντας τις οδηγίες θα πρέπει να φτάσετε σε ένα τέτοιο αποτέλεσμα.

Οι λεπτομέρειες
Τώρα, θα προσθέσουμε ένα μικρό μενού στην κορυφή του παραθύρου, όπου θα υπάρχει η επιλογή για φόρτωση ενός αρχείου. Από αυτήν, θα μπορείτε να φορτώνετε τα ψευτο-CSV αρχεία με τα περιεχόμενα των τευχών μας. Κάντε διπλό κλικ στο “Type Here” και μετονομάστε το σε Αρχείο. Με τον ίδιο τρόπο προσθέστε δύο επιλογές σε αυτό το μενού: “Ανοιγμα CSV” και “Εξοδος”. Τέλος, από τον Action Editor του QtDesigner μετονομάστε το action_CSV σε openAct και το action σε quitAct. Είμαστε έτοιμοι. Πατήστε Ctrl+R για να δείτε τι καταφέρατε και Ctrl+S για αποθήκευση.

Την δεύτερη καρτέλα με το TableView δεν θα την πειράξουμε. Πηγαίνετε στο φάκελο όπου αποθηκεύσατε τη φόρμα, ανοίξτε το αρχείο artadminform.ui και αντικαταστήστε τις γραμμές:

<class> bookAdminForm</class>
<widget class="QMainWindow" name="bookAdminForm" >

με αυτές:

<class>artAdminForm</class>
<widget class="QMainWindow" name="artAdminForm" >

και αποθηκεύστε το. Μια που είστε εκεί, μετονομάστε τα bookadmin.* σε artadmin.*.

Πίνακας στην MySQL
Η βάση δεδομένων μας αυτή τη φορά θα λέγεται articlesdb και θα έχει έναν πίνακα, το articles. Συνδεθείτε στην κονσόλα της MySQL, δίνοντας π.χ.:

mysql -udimitris -p

και φτιάξτε τη βάση με την εντολή:

CREATE DATABASE articlesdb DEFAULT CHARACTER SET utf8
COLLATE utf8_ unicode_ci;

Η βάση μας είναι έτοιμη – και για Ελληνικά! Τώρα φτιάξτε το table, δίνοντας:

CREATE TABLE articles (id int not null auto_increment primary key,
title varchar(50), editor varchar(40), issue int, month varchar(20),
type varchar(20), pages varchar(8), summary varchar (300));

Με αυτήν, δημιουργούμε τον πίνακα articles με όλα τα απαραίτητα πεδία!

Ο κώδικας
Τώρα, θα πρέπει να έχετε μία έτοιμη φόρμα, τρία αρχεία με τον παλιό κώδικα (μετονομασθέντα σε artadmin.h, artadmin.cpp και main.cpp) καθώς και το artadmin.pro. Αν δεν το κάνατε πριν, μετονομάστε τώρα αυτά τα αρχεία από bookadmin.* σε artadmin.*.

Την προηγούμενη φορά, είπαμε μερικά πράγματα για τις SQL κλάσεις της Qt. Δεν θα επεκταθούμε παραπάνω εδώ, επειδή μας αρκούν. Ανοίξτε λοιπόν το main.cpp και αρχίστε τις αλλαγές. H main ουσιαστικά χρειάζεται αλλαγές στην 1η γραμμή, όπου αλλάζετε το header σε

#include "artadmin.h"

αλλά και 6η γραμμή για να αλλάξετε την βάση δεδομένων:

db.setDatabaseName("articlesdb");

και φυσικά στις γραμμές 22 και 23, πρέπει να αλλάξετε τα BookAdmin σε Artadmin:

Artdmin artadmin;
artadmin.show();

Στα άλλα δύο αρχεία, οι αλλαγές είναι μεγαλύτερες, γι’ αυτό ας τα δούμε από την αρχή. Να ο κώδικας του artadmin.h:

#ifndef ARTADMIN_H
#define ARTADMIN_H
#include
#include "ui_artadminform.h" 
 
class ArtAdmin : public QMainWindow {
    Q_OBJECT 
 
public:
	ArtAdmin();
	QTableView *initTableView(const QString &amp;title,
	QSqlTableModel *model);
	void initModel( QSqlTableModel *model, QString filter);
private slots:
	void search();
	void loadFile();
	void clearAll();
private:
	Ui::artAdminForm ui;
	QSqlTableModel model;
	QSqlQuery query;
}; 
 
#endif

Αν το συγκρίνετε με το header αρχείο της κλάσης BookAdmin του προηγούμενου τεύχους, θα διαπιστώσετε ότι ουσιαστικά έχουμε κρατήσει ανέπαφες μόνο τις μεθόδους initTableView(), initModel(). Θυμίζω ότι η πρώτη αρχικοποιεί το TableView της 2ης καρτέλας του GUI με ένα“μοντέλο”, το οποίο προέρχεται από την initModel(). To “μοντέλο” στην αργκό της Qt είναι απλά τα δεδομένα μας, τα οποία “τραβάμε” από την MySQL (δείτε το προηγούμενο τεύχος, για περισσότερα!). Την προηγούμενη φορά, όμως, η initModel() είχε μόνο μία παράμετρο QSqlTableModel – αυτή την φορά την επεκτείναμε με μία ακόμα QString η οποία θα λειτουργεί ως φίλτρο. Δεν σας είπα ότι θα προσθέσουμε νέα κόλπα; Να ένα!

Επιπλέον, έχουν αλλάξει όλα τα ιδιωτικά slots. Θυμίζω ξανά ότι τα slots είναι ένα βασικό ατού της Qt. Πρόκειται για συναρτήσεις που μπορούν να “συνδεθούν” με signals (σινιάλα) άλλων συναρτήσεων μιας κλάσης ή στοιχείων της φόρμας έτσι ώστε να καλούνται αυτόματα. Στην περίπτωσή μας π.χ. όταν το κουμπί searchBt εκπέμπει το σινιάλο clicked(), θα καλείται αυτόματα η slot συνάρτηση search(). Τη σύνδεση των signals με τα slots θα την δούμε στην υλοποίηση της constructor ArtAdmin() σε λίγο. Τέλος, έχουμε προσθέσει μία μεταβλητή QSqlQuery, στην οποία θα αποθηκεύουμε τα ερωτήματά μας προς την MySQL.

Ας δούμε τώρα το artadmin.cpp. Εκεί έχουμε τις υλοποιήσεις των μεθόδων. Ωστόσο, η πρώτη και βασικότερη αλλαγή είναι στη 2η γραμμή, όπου αντί του bookadmin.h κάνουμε include το νέο header αρχείο, δηλαδή το artadmin.h.

#include "artadmin.h"

Αν ξεχάσετε να το κάνετε αυτό, η μεταγλώττιση θα βγάζει λάθη! Να, τώρα, η υλοποίηση της constructor μεθόδου της κλάσης ArtAdmin:

ArtAdmin::ArtAdmin() {
        ui.setupUi(this);
	connect (ui.openAct,SIGNAL(triggered()), this,SLOT(loadFile()));
	connect (ui.searchBt,SIGNAL(clicked()), this,SLOT(search()));
	connect (ui.clearBt,SIGNAL(clicked()), this,SLOT(clearAll()));
	initModel(&amp;model, "null");
	QTableView *view1 = initTableView(QObject::tr("Database"), &amp;model);
	view1->show();
	this->setWindowTitle("ArtAdmin - Greek Linux Format article
catalogue");
	this->resize(800,600);
	ui.tabWidget->setCurrentIndex(0);
}

Μπορεί να τρομάζει, αλλά ουσιαστικά δεν διαφέρει ιδιαίτερα από το προηγούμενο τεύχος. Έχουμε απλώς προσθέσει τρεις νέες δηλώσεις connect (αντί της μίας που είχε το BookAdmin) που συνδέουν τα εξής στοιχεία:

– την επιλογή “Ανοιγμα CSV” του μενού της φόρμας μας (ui.openAct) με την μέθοδο loadFile(), για να επιλέξει ο χρήστης ένα αρχείο CSV.
– το κουμπί “Αναζήτηση” της φόρμας (ui.searchBt) με την μέθοδο search(), για να γίνει μια αναζήτηση στη βάση δεδομένων με βάση μια λέξη-κλειδί.
– το κουμπί “Καθαρισμός” (ui.clearBt) με την μέθοδο clearAll(), ώστε να καθαριστούν τα περιεχόμενα όλων των πεδίων της φόρμας αλλά και το μοντέλο.

Τέλος, έχουμε αλλάξει την WindowTitle, ώστε ο τίτλος του παραθύρου μας να αντικατοπτρίζει το τι κάνει το ArtAdmin. Όλα τα υπόλοιπα έχουν μείνει ίδια. Όλα; Όχι βέβαια! Έχουμε αλλάξει και την initModel() στην 6η γραμμή, δίνοντας της μια δεύτερη παράμετρο – ένα string “null”. Όπως θα δούμε στην υλοποίηση της initModel(), με αυτόν τον τρόπο της λέμε να αρχικοποιήσει το μοντέλο, δηλαδή να τραβήξει τα δεδομένα από την βάση μας χωρίς κάποιο φίλτρο (null). Το αποτέλεσμα είναι ότι, μόλις τρέχουμε το ArtAdmin, το View widget του (το TableView που αρχικοποιήσαμε στην προηγούμενη γραμμή) θα προβάλλει όλα τα άρθρα που υπάρχουν στη βάση μας. Δεν είναι δύσκολο, σωστά;

Εισαγωγή άρθρων
Για την initTableView() ο κώδικας δεν έχει αλλάξει καθόλου, γι’ αυτό δεν θα την παραθέσουμε ξανά εδώ. Δείτε το προηγούμενο τεύχος ξανά για να την θυμηθείτε! Περνάμε τώρα στο ζουμί, δηλαδή στις μεθόδους loadFile() και search(). Η πρώτη, όπως είπαμε, καλείται από την επιλογή Άνοιγμα CSV του μενού του ArtAdmin, φορτώνει ένα αρχείο με άρθρα που επιλέγει ο χρήστης και στέλνει ότι δεδομένα βρει στην MySQL. Να ο κώδικας της:

void ArtAdmin::loadFile() {
	QString fileName = QFileDialog::getOpenFileName(this,
tr("Open File"), 0,tr("Text files (*.txt)"));
	if (fileName.isEmpty()) {
		QMessageBox::critical(this,"Failure", tr("No filename!"),
"OK",0);
		return;
	}
	QFile file ( fileName );
	if ( ! file.open(QIODevice::ReadOnly )) return;
	QString str;
	QTextStream ts( &amp;file );
	while ( !ts.atEnd() )   {
		str= ts.readLine();
		QStringList article = str.split("*");
		query.prepare("insert into articles(id,  title, editor, issue,
month, type, pages, summary) values ('', :title, :editor, :issue, :month,
:type, :pages, :summary)");
		query.bindValue(":title", article.at(0).trimmed());
		query.bindValue(":editor", article.at(1).trimmed());
		query.bindValue(":issue", article.at(2).trimmed());
		query.bindValue(":month", article.at(3).trimmed());
		query.bindValue(":type", article.at(4).trimmed());
		query.bindValue(":pages", article.at(5).trimmed());
		query.bindValue(":summary", article.at(6).trimmed());
		if(!query.exec() ) {
			QMessageBox::critical(this,"Failure", tr("Couldn't
execute query!"),"OK",0);
			return;
		}
		filter="null";
		initModel(&amp;model, filter);
	}
}

Στην 2η γραμμή, ανοίγουμε ένα διάλογο επιλογής αρχείων, με τίτλο “Open File” και του λέμε να παρουσιάσει στο χρήστη μόνο τα αρχεία του τρέχοντος φακέλου που έχουν κατάληξη .txt. Η getOpenFileName επιστρέφει πάντα το πλήρες path του επιλεγμένου αρχείου. Αν ο χρήστης δεν επιλέξει κάτι, όμως, εμφανίζουμε ένα μήνυμα σφάλματος και τερματίζουμε τη μέθοδο. Διαφορετικά, δημιουργούμε ένα αντικείμενο file στο οποίο περνάμε το πλήρες path (filename) και λέμε στην Qt να το ανοίξει μόνο για ανάγνωση (δεν θέλουμε να πειράζουμε τα CSV αρχεία μας!).

Στη 10η γραμμή, αντιστοιχίζουμε το αρχείο file με μια ροή κειμένου QTextStream, μια και ξέρουμε ότι εκεί υπάρχει μόνο κείμενου. Αμέσως μετά ξεκινάμε μια επανάληψη, που τερματίζει μόνο όταν φτάσουμε στο τέλος της ροής ts, δηλαδή στο τέλος του επιλεγμένου αρχείου. Μέσα στην επανάληψη αποθηκεύουμε κάθε γραμμή του κειμένου σε ένα ξεχωριστό string, το str. Ύστερα, με την spli(“*”) σπάμε το string σε κομμάτια, τα οποία διαχωρίζονται από τον χαρακτήρα “*”, και τα αποθηκεύουμε σε μια λίστα από strings, την article. Έτσι αν το string περιέχει Ν αστεράκια, το article θα είναι μια λίστα N+1 στοιχείων. Τώρα που έχουμε τα δεδομένα ενός άρθρου, ετοιμάζουμε και εκτελούμε το query μας, όπως ακριβώς κάναμε και στο BookAdmin για την καταχώρηση ενός βιβλίου – προσαρμοσμένο φυσικά για τον νέο πίνακα articles. Η μόνη διαφορά είναι το δεύτερο όρισμα BindValue(), όπου περνάμε μεταβλητές της μορφής: article.at(0).trimmed(). Αυτό σημαίνει “δώσε μου τα δεδομένα του 1ου στοιχείο υ της λίστας, χωρίς όμως κενά στην αρχή ή το τέλος”. Δηλαδή η trimmed() αφαιρεί τα περιττά κενά στα άκρα ενός string.

Αναζήτηση άρθρων
Ας δούμε τώρα την search(). Αυτή καλείται όταν ο χρήστης γράψει κάτι στο πεδίο αναζήτησης και κάνει κλικ στο κουμπί “Αναζήτηση”:

void ArtAdmin::search() {
	QString searchkeys= ui.searchLE->text();
	if (searchkeys.isEmpty()) {
		QMessageBox::critical(this,"Failure", tr("No search terms!"),
"OK",0);
		return;
	}
	QString qstr="SELECT * FROM articles WHERE (editor) like
(\"%"+ searchkeys +"%\") OR (title) like (\"%"+ searchkeys +"%\") ";
	filter = "(editor) like (\"%"+ searchkeys +"%\") OR (title) like
(\"%"+ searchkeys +"%\") ";
	query.prepare(qstr);
	if(!query.exec() ) {
			QMessageBox::critical(this,"Failure",
tr("Couldn't execute search query!"),"OK",0);
			return;
	}
	else
		while (query.next()) {
			ui.titleLE->insert(query.value(1).toString());
			ui.editorLE->insert(query.value(2).toString());
			ui.issueLE->insert(query.value(3).toString());
			ui.monthLE->insert(query.value(4).toString());
			ui.typeLE->insert(query.value(5).toString());
			ui.pagesLE->insert( query.value(6).toString());
			ui.textBrowser->setPlainText(query.value(7).
toString());
			break;
     		} 
 
	initModel(&amp;model, filter);
}

Είναι μεγάλο κομμάτι κώδικα, αλλά δεν έχει δυσκολίες. Στην 1η γραμμή, αποθηκεύουμε τις λέξεις-κλειδιά από το searchLE στην searchKeys, την οποία χρησιμοποιούμε στις επόμενες γραμμές για να δημιουργήσουμε ένα πρωτόγονο query αναζήτησης και το φίλτρο για το model (δείτε πλαίσιο “Φίλτρα”). Εάν το query είναι σωστό, τότε διατρέχουμε τις εγγραφές που επέστρεψε και τοποθετούμε την τιμή κάθε στοιχείου τους στα αντίστοιχα πεδία (titleLE, editorLE, κοκ). Προφανώς γνωρίζουμε ότι το στοιχείο 0 θα είναι το id (το παραλείπουμε), το στοιχείο 1 είναι ο τίτλος, το στοιχείο 2 ο συντάκτης κοκ του άρθρου, άρα δεν υπάρχει περίπτωση λάθους εδώ. Μόλις τελειώσουμε με το πρώτο άρθρο που ταίριαξε με τις λέξεις-κλειδιά, σταματάμε με την break (δείτε το πλαισιο “Βελτιώστε το!”). Τέλος, καλούμε την initModel, μόνο που αυτή τη φορά, φιλτράρουμε τα δεδομένα με το φίλτρο που φτιάξαμε στην αρχή.

Στη μέθοδο initModel(), δεν αλλάξαμε τίποτε. Μόνη προσθήκη είναι ότι οι γραμμές:

	if (filter!="null")
		model->setFilter(filter);

Δηλαδή, ελέγχουμε ότι το φίλτρο δεν είναι “null”. Αν δεν είναι, το παιρνάμε στο μοντέλο δεδομένων με την setFilter, ώστε να ανανεωθεί το TableView αυτόματα.

Το τελικό “προϊόν”
Τελειώσαμε! Ανοίξτε το αρχείο artadmin.pro και σιγουρευτείτε ότι γράφει τα εξής:

QT += sql
 
HEADERS     = artadmin.h
FORMS       = artadminform.ui
SOURCES     = main.cpp\
                artadmin.cpp

Σώστε και έπειτα δώστε τα εξής για την μεταγλώττιση του ArtAdmin:

qmake-qt4
make

Μόλις τελειώσει τρέξτε το με ./artadmin. Θα πρέπει όμως να έχετε δημουργήσει τη βάση δεδομένων και τον πίνακα όπως είπαμε στην αρχή – διαφορετικά δεν θα δουλέψει! Έπειτα, από το μενού Αρχείο, επιλέξτε το “Άνοιγμα CSV” και επιλέξτε το αρχείο 19-csv.txt. Αν όλα πάνε καλά, θα πρέπει να δείτε τα περιεχόμενα του τεύχους 18, στην 2η καρτέλα. Για να δοκιμάσετε την αναζήτηση γράψτε μια λέξη στο τελευταίο πεδίο της 1ης καρτέλας και πατήστε “Αναζήτηση”. Τα υπόλοιπα, νομίζω ότι είναι αυτονόητα. Φυσικά, τίποτα δεν είναι τέλειο – δείτε το “Βελτιώστε το” για μερικές προτάσεις… Καλό coding!


Η τελική μας εφαρμογή. Εδώ έδωσα έναν όρο αναζήτησης και να τι μου επέστρεψε…


Το ArtAdmin εν πλήρη δράση. Εδώ δείχνει όλα τα περιεχόμενα του τεύχους 19. Το αρχείο 18.csv.txt θα το βρείτε στο tarball με τον κώδικα…

ΒΕΛΤΙΩΣΤΕ ΤΟ!
Tο ArtAdmin υστερεί σε έναν κρίσιμο τομέα. Στην αναζήτηση άρθρων, τα queries ψάχνουν μόνο στον τίτλο, τον συντάκτη και την περίληψη του άρθρου. Θα ήταν χρήσιμο να επεκτείνετε την αναζήτηση και στο μήνα ή στην ενότητα αν θέλετε να βλέπετε π.χ. όλα τα άρθρα του τεύχους 3 ή όλα τα αφιερώματα. Επίσης, μπορείτε να βελτιώσετε την ακρίβεια της αναζήτησης, κάνοντας τα queries να υποστηρίζουν και λέξεις-κλειδιά σε λογικό AND. Τέλος, μπορείτε να χρησιμοποιήσετε full-text search – δειτε tinyurl.com/2e9fx5 και tinyurl.com/7tr6v. Σε αυτήν την περίπτωση όμως οι συχνές λέξεις δεν θα γίνονται match…

Κατεβάστε όλον τον κώδικα από εδώ:

Αναδημοσίευση από το τεύχος 19 του Ελληνικού Linux Format.