<?xml version="1.0" encoding="utf-8"?>
<page xmlns="http://projectmallard.org/1.0/" type="topic" id="howto_write_a_plugin" xml:lang="az">
  <info>
    <link type="guide" xref="index#advanced"/>
    <title type="sort">3. Yeni əlavələrin yazılması</title>
    <link type="next" xref="preferences"/>
    <desc><app>Accerciser</app>-ə istədiyiniz funksiyaları əlavə etmə</desc>
    <credit type="author">
      <name>Eitan Isaacson</name>
      <email>eitan@ascender.com</email>
    </credit>
    <credit type="author">
      <name>Peter Parente</name>
      <email>pparent@us.ibm.com</email>
    </credit>
    <credit type="author">
      <name>Aline Bessa</name>
      <email>alibezz@gmail.com</email>
    </credit>
    <license>
      <p>Creative Commons Eyni Şərtlərlə Paylaş 3.0</p>
    </license>
  
    <mal:credit xmlns:mal="http://projectmallard.org/1.0/" type="translator copyright">
      <mal:name>Tərcümə: Ramal Rəhimov</mal:name>
      <mal:email>jhonaluman@gmail.com</mal:email>
      <mal:years>2025</mal:years>
    </mal:credit>
  </info>
  <title><app>Accerciser</app> üçün əlavələrin yazılması</title>
  <p><app>Accerciser</app>-ə yeni əlavələr əlavə etmək <link href="https://wiki.gnome.org/Apps/Accerciser/PluginTutorial">bu dərslik</link> yazıldıqdan sonra daha da sadələşdi. Dərslik mövzunu ətraflı izah etdiyindən, bu bölmə əsasən onun orijinal məzmunundan ibarətdir – sadəcə kiçik redaktələr və yeniləmələr edilmişdir.</p>
  <p><app>Accerciser</app> üç əsas əlavə növünü dəstəkləyir:</p>
  <list>
    <item>
      <p>Əsas əlavələr – Bu əlavələr Plugin əsas sinfindən törəmişdir. Onlar görünən interfeys təqdim etmirlər, lakin <app>Accerciser</app>-ə əlavə funksionallıq təmin edə bilərlər.</p>
    </item>
    <item>
      <p>Konsol əlavələri – Bu əlavələr əlavələr panelindəki mətn sahəsinə sadə konsol çıxışı təmin edir. Onları paketlənmiş <link xref="ipython_plugin">IPython Konsol Əlavəsi</link> ilə qarışdırmayın.</p>
    </item>
    <item>
      <p>Baxış paneli əlavələri – <app>Accerciser</app>-in əksər standart əlavələri bu növdəndir. Bunlar ayrıca vərəqdə xüsusi qrafik interfeys təqdim edir.</p>
    </item>
  </list>

  <section id="base_plugin">
    <title>Əsas Əlavənin Yaradılması</title>
    <p><link xref="quick_select_plugin">Sürətli Seçim Əlavəsi</link>-nin sadələşdirilmiş versiyasını yaradacağıq. Bu əlavə <keyseq><key>Ctrl</key><key>Alt</key><key>E</key></keyseq> düymələrinə basıldıqda son fokuslanmış əlçatan elementi seçəcək.</p>
    <p>Əvvəlcə istifadə edəcəyimiz import sətirləri bunlardır:</p>
    <code>
      from accerciser.plugin import Plugin
      import gtk
      import pyatspi
    </code>
    <p>Sonra Plugin əsas sinfindən yeni bir sinif yaradacağıq və ona bəzi vacib sinif atributlarını təyin edəcəyik:</p>
    <code>
      class FocusSelect(Plugin):
        plugin_name = 'Fokus Seçimi'
        plugin_description = 'Son fokuslanmış əlçatan obyektin seçilməsinə imkan verir.'
    </code>
    <p>İndi <code>init</code> metodunu yenidən müəyyən edəcəyik. Burada son fokuslanmış əlçatan obyektin seçilməsi üçün qlobal düymə əməliyyatı təyin edəcəyik, "fokus" hadisəsi üçün dinləyici qeydiyyatdan keçirəcəyik və <cmd>last_focused</cmd> dəyişənini <cmd>None</cmd> olaraq təyin edəcəyik.</p>
    <code>
      def init(self):
        pyatspi.Registry.registerEventListener(self.accEventFocusChanged, 'focus')
        self.global_hotkeys = [('Son fokuslanmış əlçatan obyektə baxış',
                                self.inspectLastFocused,
                                gtk.keysyms.e,
                                gtk.gdk.CONTROL_MASK | gtk.gdk.MOD1_MASK)]
        self.last_focused = None
    </code>
    <p><cmd>global_hotkeys</cmd> nümunə dəyişəninin siyahı şəklində qoşalılardan ibarət olduğunu nəzərə alın. Hər bir qoşalı qlobal qısayol əməliyyatını təmsil edir – bu əməliyyat təsviri, çağırılacaq metod, düymə simvolu və düymə dəyişdirici maskasından ibarətdir.</p>
    <p>"fokus" hadisəsinin geri çağırılmasında, <cmd>last_focused</cmd> nümunə dəyişənini bu hadisəni göndərmiş əlçatan obyektlə doldururuq.</p>
    <code>
      def accEventFocusChanged(self, event):
        if not self.isMyApp(event.source):
          self.last_focused = event.source
    </code>
    <p>Qısayol düyməsinin əməliyyatı üçün geri çağırmada, əgər qeyd olunubsa, tətbiqdəki əsas düyünü son fokuslanmış əlçatan obyektlə yeniləyirik:</p>
    <code>
      def inspectLastFocused(self):
        if self.last_focused:
          self.node.update(self.last_focused)
    </code>
  </section>
  <section id="console_plugin">
    <title>Konsol Əlavəsinin Yaradılması</title>
    <p>"Push button" (təzyiq düyməsi) roluna malik əlçatan element tərəfindən göndərilən fokus dəyişikliklərini göstərmək üçün konsol əlavəsi yaradacağıq — unutmayın ki, hər hansı bir elementin rolunu <app>Accerciser</app> vasitəsilə asanlıqla yoxlamaq olar; məsələn, bunu <link xref="desktop_tree_view">Tətbiq Ağacı Baxışında</link> yoxlaya bilərsiniz.</p>
    <p>Tələb olunan import sətirləri bunlardır:</p>
    <code>
      from accerciser.plugin import ConsolePlugin
      import pyatspi
    </code>
    <p>Sonra bir sinif təyin edirik və ona əlavənin adını və təsvirini əlavə edirik:</p> 
    <code>
      class PushButtonFocus(ConsolePlugin):
        plugin_name = 'Basılan Düymə Fokus'
        plugin_description = 'Basılan düymə fokuslandıqda hadisəni çap edir.'
    </code>
    <p>init metodunu yenidən yazırıq və dinləyici qeydiyyatını əlavə edirik:</p>
    <code>
       def init(self):
         pyatspi.Registry.registerEventListener(self.accEventFocusChanged, 'focus')
    </code>
    <p>Geri çağırma metodunda bütün basılan düymə hadisələri çap olunur.</p>
    <code>
      def accEventFocusChanged(self, event):
        if event.source.getRole() == pyatspi.ROLE_PUSH_BUTTON:
          self.appendText(str(event)+'\n')
    </code>
  </section>
  <section id="viewport_plugin">
    <title>Qrafik Görünüşlü Əlavənin Yaradılması</title>
    <p>AT-SPI Əməliyyat interfeysini dəstəkləyən və "click" adlı əməliyyatı olan əlçatan obyektlərdə </p>
    <p>Əvvəlcə vacib olan bəzi import sətirləri:</p>
    <code>
      import gtk
      from accerciser.plugin import ViewportPlugin
    </code>
    <p>Sonra isə bir sinif təyini, adı və təsviri ilə birlikdə:</p>
    <code>
      class Clicker(ViewportPlugin):
        plugin_name = 'Klikləyici'
        plugin_description = 'Əlçatan obyektlərdə "click" əməliyyatını yoxlayır.'
    </code>
    <p>`init` metodunu yenidən yazırıq, burada bir istifadəçi interfeysi qururuq və düyməyə siqnal üçün geri çağırma funksiyası qoşuruq. Düymənin əlavənin səhifəsində ortalanması və bütün sahəni tutmaması üçün düzülüşü təyin edirik. Nəzərə alın ki, <cmd>plugin_area</cmd> dəyişəni `gtk.Frame` obyektidir və bu sahə bütün əlavə vidcetləri ilə doldurula bilər.</p>
    <code>
       def init(self):
         self.click_button = gtk.Button('Klikləyin!')
         self.click_button.set_halign(gtk.Align.CENTER)
         self.click_button.set_valign(gtk.Align.CENTER)
         self.plugin_area.add(self.click_button)

         self.click_button.connect('clicked', self.onClick)

         self.show_all()
    </code>
    <p>Bundan əlavə, cari seçilmiş əlçatan obyektin dəstəklədiyi əməliyyatların siyahısını qaytaran köməkçi metod yaratmışıq – əgər bu obyekt Action interfeysini dəstəkləmirsə, boş siyahı qaytarır:</p> 
    <code>
       def accSupportedActions(self):
       try:
         ai = self.node.acc.queryAction()
       except NotImplementedError:
         action_names = []
       else:
         action_names = [ai.getName(i) for i in xrange(ai.nActions)]
       return action_names
    </code>
    <p>Əsas əlavə sinifində `onAccChanged` adlı metod var və bu metod hədəf tətbiqin seçilmiş əlçatan obyektində dəyişiklik olduqda çağırılır. Bu metodu yenidən yazaraq düymənin yalnız cari obyektin "click" əməliyyatını dəstəklədiyi halda aktivləşməsini təmin edəcəyik:</p>
    <code>
       def onAccChanged(self, acc):
         has_click = 'click' in self.accSupportedActions()
         self.click_button.set_sensitive(has_click)
    </code>
    <p>Düymənin "clicked" siqnalı üçün geri çağırma funksiyası cari əlçatan obyekt üzərində "click" əməliyyatını icra edir. Bu funksiyanın yalnız düymə aktiv olduqda çağırıla biləcəyini bildiyimiz üçün, obyektin "click" əməliyyatına malik olub-olmadığını ayrıca yoxlamağa ehtiyac yoxdur.</p>
    <code>
      def onClick(self, button):
        ai = self.node.acc.queryAction()
        action_names = [ai.getName(i) for i in xrange(ai.nActions)]
        ai.doAction(action_names.index('click'))
    </code>
   </section>
</page>
