İçindekiler Tablosu

Önceki konu

KActions Kullanımı

Sonraki konu

Komut Satırı Argümanları

Bu Sayfa

Dosya Açma ve Kaydetme

Giriş

Önceki örneklerimizde yavaş yavaş basit bir düzenleyici arayüzü oluşturduk. Görünüşten sonra işlevsel olarak da bir metin düzenleyiciye yaklaşmak için birkaç ekleme daha yapalım şimdi de. Bir metin düzenleyici temel olarak sabit diskteki dosyaları açabilmeli, düzenlediğiniz dosyaları kaydedebilmeli ve sıfırdan yeni dosyalar oluşturabilmeli.

KDE, dosyalar üzerinde çalışmak için geliştiricilerin hayatını kolaylaştıran pek çok sınıf sunar. KIO kütüphanesi ağ şeffaf protokoller ve standart dosya iletişim pencereleri aracılığıyla dosyalara kolayca erişmenizi sağlar.

../_images/acmakaydetme01.png

Kod

Kodlamaya önceki örneğimizdekiyle hemen hemen aynı bir main.cpp dosyasıyla başlıyoruz:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
#include <KApplication>
#include <KAboutData>
#include <KCmdLineArgs>

#include "mainwindow.h"

int main (int argc, char *argv[])
{
  KAboutData aboutData( "tutorial4", "tutorial4",
      ki18n("Tutorial 4"), "1.0",
      ki18n("A simple text area which can load and save."),
      KAboutData::License_GPL,
      ki18n("Copyright (c) 2013 Developer") );
  KCmdLineArgs::init( argc, argv, &aboutData );
  KApplication app;

  MainWindow* window = new MainWindow();
  window->show();
  return app.exec();
}

Metin düzenleyimizin dosyaları açma ve kaydetme yetenekleriyle donatmak istediğimiz için bu işleri yapacak fonksiyonlar eklemeliyiz. Fonksiyonlar Qt’nin sinyal/yuva mekanizması üzerinden çağrıldığından bu fonksiyonları yuva olarak tanımlamalıyız. Başlık dosyasında yuva kullandığımız için de Q_OBJECT makrosunu eklemeliyiz.

Ayrıca açılan dosyaları takip etmek istediğimiz için fileName isminde bir QString deklare ediyoruz.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <KXmlGuiWindow>
#include <KTextEdit>

class MainWindow : public KXmlGuiWindow
{
  Q_OBJECT

  public:
    MainWindow(QWidget *parent=0);

  private:
    KTextEdit* textArea;
    void setupActions();
    QString fileName;

  private slots:
    void newFile();
    void openFile();
    void saveFile();
    void saveFileAs();
    void saveFileAs(const QString &outputFileName);
};

#endif

Önceki örnektekinden çok da farklı olmayan bir tutorial4ui.rc oluşturuyoruz. KDE’nin kendisi halledeceği için KStandardActions eylemlerinin yerleşimi hakkında herhangi bir bilgi eklememiz gerekmiyor.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
<?xml version="1.0" encoding="UTF-8"?>
<gui name="tutorial4"
     version="1"
     xmlns="http://www.kde.org/standards/kxmlgui/1.0"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://www.kde.org/standards/kxmlgui/1.0
                         http://www.kde.org/standards/kxmlgui/1.0/kxmlgui.xsd" >

  <MenuBar>
    <Menu name="file" >
      <Action name="clear" />
    </Menu>
  </MenuBar>

  <ToolBar name="mainToolBar" >
    <text>Main Toolbar</text>
    <Action name="clear" />
  </ToolBar>

</gui>

Şimdi mainwindow.cpp dosyasını detaylıca inceleyelim:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
#include "mainwindow.h"

#include <KApplication>
#include <KAction>
#include <KLocale>
#include <KActionCollection>
#include <KStandardAction>

#include <KFileDialog>
#include <KMessageBox>
#include <KIO/NetAccess>
#include <KSaveFile>
#include <QTextStream>

MainWindow::MainWindow(QWidget *parent)
    : KXmlGuiWindow(parent),
      fileName(QString())
{
  textArea = new KTextEdit;
  setCentralWidget(textArea);

  setupActions();
}

void MainWindow::setupActions()
{
  KAction* clearAction = new KAction(this);
  clearAction->setText(i18n("Clear"));
  clearAction->setIcon(KIcon("document-close"));
  clearAction->setShortcut(Qt::CTRL + Qt::Key_W);
  actionCollection()->addAction("clear", clearAction);
  connect(clearAction, SIGNAL(triggered(bool)),
          textArea, SLOT(clear()));

  KStandardAction::quit(kapp, SLOT(quit()),
                        actionCollection());

  KStandardAction::open(this, SLOT(openFile()),
                        actionCollection());

  KStandardAction::save(this, SLOT(saveFile()),
                        actionCollection());

  KStandardAction::saveAs(this, SLOT(saveFileAs()),
                        actionCollection());

  KStandardAction::openNew(this, SLOT(newFile()),
                        actionCollection());

  setupGUI();
}

void MainWindow::newFile()
{
  fileName.clear();
  textArea->clear();
}

void MainWindow::saveFileAs(const QString &outputFileName)
{
  KSaveFile file(outputFileName);
  file.open();

  QByteArray outputByteArray;
  outputByteArray.append(textArea->toPlainText().toUtf8());
  file.write(outputByteArray);
  file.finalize();
  file.close();

  fileName = outputFileName;
}

void MainWindow::saveFileAs()
{
  saveFileAs(KFileDialog::getSaveFileName());
}

void MainWindow::saveFile()
{
  if(!fileName.isEmpty())
  {
    saveFileAs(fileName);
  }
  else
  {
    saveFileAs();
  }
}

void MainWindow::openFile()
{
  QString fileNameFromDialog = KFileDialog::getOpenFileName();

  QString tmpFile;
  if(KIO::NetAccess::download(fileNameFromDialog, tmpFile, this))
  {
    QFile file(tmpFile);
    file.open(QIODevice::ReadOnly);
    textArea->setPlainText(QTextStream(&file).readAll());
    fileName = fileNameFromDialog;

    KIO::NetAccess::removeTempFile(tmpFile);
  }
  else
  {
    KMessageBox::error(this,
        KIO::NetAccess::lastErrorString());
  }
}

Yaptığımız ilk şey MainWindow kurucusuna fileName(QString()) ifadesini eklemek. Bu, ilk başlangıç anından itibaren fileName’in boş olmasını garanti ediyor.

Sonra KStandardActions eylemleriyle kullanıcıların uygulamaya dosyayı yüklemesini veya kaydetmesini söyleyebileceği dış arayüzü oluşturuyoruz. Eylemlerin hepsini de başlık dosyasında deklare ettiğimiz uygun yuvalara bağlıyoruz.

Oluşturduğumuz ilk fonksiyon yeni bir belge oluşturan newFile() fonksiyonu. fileName.clear(), henüz belge sabit disk üzerinde kayıtlı olmadığı için fileName isimli QString’i boş olarak ayarlar. Sonra textArea->clear() da merkezi metin alanının içini temizler.

Şimdi ilk dosya işleme kodumuzun üzerindeyiz. Metin alanının içeriğini parametre olarak verilen dosya ismine kaydeden bir fonksiyon gerçekleştireceğiz. KDE dosyaları güvenle kaydetmek için Qt’nin QFile sınıfından türetilmiş KSaveFile sınıfı sunar.

void MainWindow::saveFileAs(const QString &outputFileName) ile fonksiyonun prototipini, KSaveFile file(outputFileName); ile KSaveFile nesnesini oluşturuyoruz ve file.open(); ile dosyayı açıyoruz.

Şimdi yazmak için hazır bir dosyaya sahibiz. Metin alanındaki metni dosyaya kaydedilebileceği şekilde biçimlendirmemiz gerekiyor. Bunun için QByteArray outputByteArray; ile bir QByteArray oluşturuyor ve outputByteArray.append(textArea->toPlainText().toUtf8()); ile içini metin alanında her ne varsa onun düz metin haliyle dolduruyoruz.

QByteArray’ı KSaveFile::write() ile dosyaya yazmak için kullanacağız. Eğer normal bir QFile kullanıyor olsaydık bu değişikliklerin hemen yansımasına neden olacaktı. Bu da yazma sırasında bir hata oluşması durumunda dosyanın bozulmasına neden olur. Bu nedenle KSaveFile ilk önce geçici bir dosyaya yazar ve KSaveFile::finalize() çağrısı yaptığınızda asıl dosyada değişiklik yapar.

Burada son olarak da fileName = outputFileName; ile MainWindow’un fileName üyesini kaydettiğimiz dosyanın ismini gösterecek şekilde ayarlıyoruz.

saveFileAs(), saveAs yuvasına bağlanan fonksiyon. Sadece genel saveFileAs(QString) fonksiyonunu çağırır ve KFileDialog::getSaveFileName() tarafından döndürülen dosya ismini geçer.

Bu KIO kütüphanesini kullandığımız ilk an. KFileDialog, genel dosya iletişim pencereleri göstermek için tüm KDE uygulamalarınca kullanılan çeşitli statik fonksiyonlar sunar. KFileDialog::getSaveFileName() çağrısı kullanıcıya dosya ismi seçebileceği bir iletişim penceresi gösterir. Fonksiyon daha sonra saveFileAs(QString) fonksiyonuna geçeceğimiz tam dosya ismini döndürür.

saveFile() fonksiyonunda yeni veya heyecen verici bir şey bulunmamakta. Sadece kaydetme iletişim penceresinin gösterilip gösterilmeyeceğini belirliyor. fileName boş değilse dosya fileName’a kaydediliyor. Ama eğer boşsa kullanıcıya isim seçebilmesi için iletişim penceresi gösteriliyor.

Sonunda sabit diskten dosya yükleyebilecek duruma geldik. Bunu yapacak kodların hepsi MainWindow::openFile() fonksiyonunda bulunuyor. İlk önce kullanıcıya açmak istediği dosya ismini sormalıyız. Bunu bir başka KFileDialog fonksiyonu olan getOpenFileName() ile yapıyoruz.

Daha sonra KIO kütüphanesini kullanarak dosyayı alıyoruz. Bu bize dosyayı QFile kullanarak FTP gibi uzak bir konumda bulunsa bile açma imkanı verir.

Sonraki çağrımızı KIO::NetAccess::download(fileNameFromDialog, tmpFile, this) ile NetAccess's download() fonksiyonuna yapıyoruz. İlk argüman yüklemek istediğimiz dosyanın ismi. İkinci argüman, dosyanın yüklenmesi tamamlandıktan sonra dosyanın geçici kopyasının konumunu saklayacak bir QString. Bundan sonra çalışacağımız dosya tmpFile.

Bu fonksiyon transferin başarılı geçip geçmediğine bağlı olarak true veya false döndürür. Eğer başarısız olursa KMessageBox::error(this, KIO::NetAccess::lastErrorString()); ile hatayı veren bir mesaj kutusu gösteriyoruz. Başarılı olursa dosyayı açarak devam ediyoruz.

QFile file(tmpFile); ile geçici dosyadan bir QFile oluşturuyor ve file.open(QIODevice::ReadOnly); ile sadece okunur kipte açıyoruz.

Dosyanın içeriğini görüntüleyebilmek için bir QTextStream kullanmalıyız. Dosyamızın içeriğini yapıcısına geçerek bir tane oluşturuyor ve sonra QFile’ın readAll() fonksiyonunu çağırarak dosyadan metni alıyoruz. Daha sonra da bunu textArea->setPlainText(QTextStream(&file).readAll()); ile metin alanımızın setPlainText() fonksiyonuna geçiyoruz.

Daha sonra yeni açtığımız dosyanın yolunu fileName = fileNameFromDialog; kaydediyoruz ve son olarak da KIO::NetAccess::removeTempFile(tmpFile); ile geçici dosyayı siliyoruz.

İnşa

Bu sefer KIO kütüphanesini de kullandığımız için target_link_libraries() fonsiyonuna ${KDE4_KIO_LIBS} değerini geçerek CMake’e KIO’yu da bağlamasını söylemeliyiz.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
project(tutorial4)

find_package(KDE4 REQUIRED)
include_directories(${KDE4_INCLUDES})

set(tutorial4_SRCS
  main.cpp
  mainwindow.cpp
)

kde4_add_executable(tutorial4 ${tutorial4_SRCS})

target_link_libraries(tutorial4 ${KDE4_KDEUI_LIBS}
                                ${KDE4_KIO_LIBS})

install(TARGETS tutorial4 DESTINATION ${BIN_INSTALL_DIR})
install(FILES tutorial4ui.rc
        DESTINATION ${DATA_INSTALL_DIR}/tutorial4)

Derleme ve Çalıştırma

Tüm dosyalarımızın yazımını tamamladığımıza göre çalıştırmak için derleyip, bağlayabiliriz:

mkdir build
cd build
cmake .. -DCMAKE_INSTALL_PREFIX=$HOME
make
make install
$HOME/bin/tutorial4

Not

Değişen ayarlar KDE’nin uygulama ayarlarını sakladığı dizinde tutulur, bu örneğimizin ayarları $HOME/.kde/share/apps/tutorial4 dizininde bulunur.