28 Ekim 2013 Pazartesi

Cehennem (Inferno) - Dan Brown


Kitabı çıktığı gün almıştım fakat okumak ve inceleme yazmak bu zamana kadar kaldı ne yazık ki. Şimdi düşünüyorum da keşke hemen okusaymışım. Uzun bir kitap okumama döneminden sonra bu kitap ilaç gibi geldi diyebilirim.

Kitap, daha ilk 10 sayfada kendine bağımlı yapmaya başlıyor insanı. Dan Brown'un tarzı, insanı çok fazla boğmayan, kısmen basit olan betimlemeleri ile oldukça kolay anlaşılır oluyor. Beğendiğim bir diğer husus ise roman içerisindeki hikaye sayısını sınırlı tutması. Yani 10 tane ayrı hikaye ile başlayıp kitabın sonunu bağlayamama gibi bir durum olmuyor. Akış ve takip edilebilme durumu, önceki kitaplarındakinde de daha iyi olmuş diyebilirim.

Gelelim konuya. Belki konuların çok ilgimi çekmesinden dolayı, ya da çok tutulan konuları seçmesinden dolayı Dan Brown'un kitaplarını merak içerisinde okuyorsunuz. Bu kitapta, insanı merakta bırakan en önemli unsur kuşkusuz ki Dante olmuş. Dante ile ilgili, fazlaca paralar saçılarak yapılacak bir reklam kampanyası bile bu kadar tutmazdı eminim. Kitabın çeşitli yerlerinde bir çok kez kendisine, yaşamına, siyasi görüşüne, eserlerine değinilmiş ve bir çok detay verilmiş. Bu kitap sonrası, hiç alakası olmayan insanların bile merak edip İlahi Komedya'yı okuyacağından eminim. Kitapta bahsi geçen eserler, belli ki çok büyük bir bilgi birikimi, çalışma ve ekip çalışması ile incelenmiş. Dan Brown'ın ve etrafındaki yardımcı insanların gerçekten de inanılmaz bir bilgi birikimine sahip olduğu söylenebilir. Mekanları ve eserleri öylesine güzel işlemişler ki, kitap okurken bir kaç kez durup Google'a araştırma gereği duydum. Müzelerde gezdiğinizde yanından geçip "güzel çizilmiş" dediğiniz eserlerin altındaki anlam, kimin için, ne amaçla yapıldığı gibi bilgileri öğrendikçe yeniden yeniden incelemek istiyorsunuz eserleri.

Kitabın geçtiği mekanlara bakacak olursak, Dan Brown'ın uzmanlık alanı olan Floransa, Venedik ve az da olsa İstanbul işlenmiş. İtalya'yı ve Floransa'yı daha önce gezmiş bir insan olarak keşke bu kitap bir kaç sene önce çıksaydı da, o eserlere daha fazla bilgi ve merak sahibi olarak baksaydım diyorum. Hikayenin geçtiği mekanlardaki gizli geçitler, çoğu kişinin dikkat etmeyeceği ufak detaylar, bundan sonra özellikle Floransa'yı gezecek insanlar için incelenecek yerler oldu artık. Gelelim İstanbul'a. Diğer şehirlerden biraz daha az değinilmiş olsa da özellikle Tarihi Yarımada ile ilgili güzel tespitler mevcut. Yabancı birileri tarafından her işlendiğindeki o fesli, sarıklı, Arabistan'a benzetilen İstanbul bu sefer daha doğru tespitlerle, ön yargılardan uzak, gerçekten de olduğu gibi işlenmiş. Yalnız bildiğiniz tanıdığınız yerlerin kitapta işlenmesinin şöyle bir dezavantajı var; konudan sapıp mekanların nasıl tanıtılmış onu takip ediyorsunuz bu sefer. Bir de neresi olduğunun merak edildiği yerler var ki biz bildiğimiz için bunları hemen tahmin edebiliyoruz ve heyecanı kalmıyor :) Bir diğer nokta ise, herkesin bir çok gezip gördüğü tarihi eserlerimiz ile ilgili bilmediğimiz detay bilgileri edinebiliyoruz kitaptan.

Senaryoya gelirsek. Akıcı ve insanı sürükleyen bir konu var yine ortada. Önceki kitaplardaki gibi belli bir amaç doğrultusunda tarih içerisinde yolculuk ediyor ve bir takım gizemler çözmeye çalışıyoruz. Hikaye ilerlerken tarihi mekanlar ve detayları ile birlikte, günümüze ait teknolojik gelişmelerden bahsedilmesi, kitapta biraz da bizden birşeyler bulmayı sağlıyor. Özellikte polisiye seven insanlar için kitapta Dan Brown'ın, kim olduğunu merak ettiğimiz karakterler arasında bir ters köşe yapması var ki dillere destan:) Fakat ne yazık ki -spoiler- Robert Langdon'ın hafızasını kaybetmesi sonrası gerçeklerin anlatıldığı esnadaki kurgu çok yavan ve basit kalmış. Truman Show tarzındaki 'Her şey bir senaryoydu' yaklaşımı bende, bir film izleyip sonrasında herşeyin rüya olmasının bıraktığı etkiyi bıraktı. Burası için daha iyi bir kurgu yapılabilirmiş bence -spoiler sonu-

İşten güçten ötürü kitabı tek seferde okuyamadım ne yazık ki fakat bir pazar günü sabahtan başlanıp bir solukta okunacak bir kitap olmuş diyebilirim. Dan Brown'ın yeni kitaplarını dört gözle bekliyor olacağım.

( dan brown, inferno, cehennem, dante, ilahi komedya, cennet, araf, istanbul, venedik, floaransa )

12 Eylül 2013 Perşembe

Primefaces Datatable Contextmenu Disappear Problem Fix

Updatable context menu is a big problem if you are using tree or datatable component of Primefaces. For example in my case, I have a datatable that has row which has different boolean flags. Depending of that flags, I have to change my context menu items. Basically, I have to render different context menus for each row in my datatable. First I tried to update context menu in element but there was a problem which I was finally able to solve...

ContextMenu component has two phases. One is generate or update phase and the other is show phase. If you try to update your context menu on right click, show phase comes first and then it updates itself. After this process, you will see that you context menu appears and disappears. While I was searching for a workaround, I found a post which helped me a lot in Primefaces forum. A guy found a solution which is overriding show function of context menu and then calling this method right after update process is done. This is the best solution I think. That guy applied this workaround for tree component. Below, you can find this approach that is applied to datatable.

<script type="text/javascript">
//patch to fix a problem that the context menu disappears after update
//delay the show to occure after the update 
var siteFunctions = {
    patchContextMenuShow: function() {
        var protShow = PrimeFaces.widget.ContextMenu.prototype.show;
        siteFunctions.patchContextMenuShow.lastEvent = null;
        PrimeFaces.widget.ContextMenu.prototype.show = function(e) {
            var ret;
            if (e) {
//saving last event
                siteFunctions.patchContextMenuShow.lastEvent = e;
                siteFunctions.patchContextMenuShow.lastEventArg = arguments;
                siteFunctions.patchContextMenuShow.lastEventContext = this;
            } else if (siteFunctions.patchContextMenuShow.lastEvent) {
//executing last event
                ret = protShow.apply(siteFunctions.patchContextMenuShow.lastEventContext, siteFunctions.patchContextMenuShow.lastEventArg);
//clearing last event
                siteFunctions.patchContextMenuShow.lastEvent = null;
            }
            return ret;
        };
    }
};

$(document).ready(function() {
    try {
        siteFunctions.patchContextMenuShow();
    } catch (e) {
        console.error(e);
    }
});
</script>

<p:contextmenu beforeshow="return true;" 
               for="dataTable" 
               id="contextMenuID" 
               widgetvar="tableContextMenuWV">
   <p:menuitem value="Menu 1" />
   <p:menuitem value="Menu 2" />
</p:contextmenu>
                
<p:datatable id="dataTable" widgetvar="dataTableW">
   <p:ajax event="contextMenu" 
           oncomplete="tableContextMenuWV.show();" 
           update=":formList:contextMenuID" />
</p:datatable>
( primefaces, jsf, datatable, row, context menu, update, show, disappear )
Kaynak : http://forum.primefaces.org/viewtopic.php?f=3&t=26813

31 Temmuz 2013 Çarşamba

Primefaces Row Toggle on Row Click

Due to the requests of people, I am going to write in English right now (for software topics).

Primefaces, which is a popular tag library for jsf has lots of different components which are pretty useful but these kid of libraries have some problems when you want to do something more detailed. I am going to help these people who are using Primefaces datatable component.

This component has a feature called rowToggler which let us toggle the row by clicking a generated triangle button. But what if you want to toggle the row by clicking anywhere on the row instead of just clicking rowTogglee button? The answer is below. I coded a little javascript stuff to make this feature work.

From one release to another, the css style names and html hierarchy may change in Primefaces. I make this code work in Primefaces v3.5.10. Putting code below to your xhtml page will make datatable rows expandable by clicking on the row:

<script type="text/javascript">
    $(document).on("click", ".ui-datatable-tablewrapper .ui-datatable-data tr.ui-widget-content", function() {
        /*1 - for expanded area*/
        if ($(this).hasClass('ui-expanded-row-content')) {
            return;
        }
        /*2 - to collapse open ones*/
        expandedRow = $('.ui-expanded-row');
        if (expandedRow.length !== 0 && !$(this).hasClass('ui-expanded-row')) {
            $('.ui-expanded-row-content').css('display', 'none');
            var untoggler = expandedRow.find('.ui-row-toggler');
            dataTableWidgetVarName.toggleExpansion(untoggler);
        }
        /*3 - for main expand feature*/
        var toggler = $(this).find('.ui-row-toggler');
        dataTableWidgetVarName.toggleExpansion(toggler);
    });

    $(document).on("click", ".ui-icon-circle-triangle-e", function() {
        if ($(this).hasClass('ui-icon-circle-triangle-s')) {
            return;
        }
        expandedRow = $('.ui-expanded-row');
        if (expandedRow.length !== 0) {
            $('.ui-expanded-row-content').css('display', 'none');
            var untoggler = expandedRow.find('.ui-row-toggler');
            dataTableWidgetVarName.toggleExpansion(untoggler);
        }
    });
</script>

First function is for the row and the second one is for the rowToggler button itself. Because of a bug in Primefaces, you cannot fire click event of the row when you click on images in the row. This is why I had to implement another click function for rowToggler button itself. You can find other descriptions below:

1 - This code block is for expanded area of the row. With this code, onthing happens when user clicks on expanded are of the row.

2 - This code brings a feature to close other expanded rows in datatable when user clicks another row.

3 - This is the main expand feature. When user clicks on the row, I am just calling toggleExpansion() function of datatable element.

Hope this post will help and guide someone who needs similar feature for datatable.

( primefaces, jsf, mojarra, datatable, row, rowToggle, toggleExpansion )

29 Haziran 2013 Cumartesi

Man Of Steel

Çok fazla çizgi roman okumuşluğum falan yoktur aslında fakat Superman'i sanırım herkes bir şekilde bilir küçüklüğünden beri. Benim için çizgi filmleri, 78 yapımı filmi ve 'Superman Returns' ibaretti aslında. Uzun zamandır sinemaya gitmediğim için ve gerçekten bu tarz bir film izlemeyi özlediğim için büyük bir heyecanla gittim aslında filme.


Öncelikle belirteyim bu 3D film furyası başladığından beri, üç boyutsuz izlemek istediğim filmleri o şekilde izleyememek, güzel senaryosu vs. olan filmlerin de üç boyutlu yapılmak uğruna efektlere falan boğulması beni en sinir eden şeydi fakat bu film o konuda çok başarılı diyebilirim. Süper kahraman filmlerindeki klasik olan dünyayı kurtarma kısımları başlamadan önceki kahramanın geçmişinin anlatıldığı kısımlar genelde çok kısa olup hemen aksiyona geçilmek istenir. Man of Steel'de bu durum çok güzel aşılmış bence. Filmin yaklaşık %20lik bir bölümünde nam-ı değer Superman'in doğuşu, gezegeninin geçmişi, dünyamıza gelişi gibi konular işlenmiş. Bu kısımlara hatta apayrı bir film gözüyle bile bakılabilir bence ve çok başarılı olmuş. Kısa kesilmemiş, insanı sıkacak kadar uzatılmamış, konu hemen geçilmemiş, efektler, aksiyon ve senaryo ile izleyiciyi ekranda tutmuş bu bölümler. Superman'in dünyaya gelişi sonrası çocukluğu, büyümesi, özelliklerini insanlardan gizleme çabası da ilk bölümden apayrı bir şekilde işlenmiş, daha sakin geçen, insanları kurtardığı bölümlerle filmin ana düşüncesinden insanları koparmayan bir bölüm olmuş. Filmin son bölümleri ise malum zaten, aksiyon patlaması. Kal-El'in zamanla dünya şartlarına adapte olup kendi gezegeninin atmosferine, materyallerine karşı zayıf düşmesi, ileride muhtemelen kendisini zor durumda bırakacak olan kriptonitin de neden buna sebep olacağını izleyiciye göstermiş ve güzel olmuş. Bunu yaparken insanın gözüne gözüne yeşil bir madde sokmayıp bu şekilde bir senaryodan gidilmesi de oldukça mantıklı olmuş. Ayrıca artık bu tarz filmlerde oldukça sık rastlanılan ufak espriler ve komiklikler de güzel bir renk katmış diyebilirim. Dünya'yı yok etme senaryosuna gelirsek, bence oldukça orijinal olmuş iki taraftan yer çekimini kullanmak. Fakat dünyayı ele geçirme sebebi için aynısını söylemeyeceğim. Arkadaşım koskoca uzayda başka gezegen mi yok da illaki dünya ile uğraşıyorsun. Al gezegeninin çocuk tarlasına sahip gemiyi ve git :) Şaka bir yana o noktada ufak bir zayıflık var ama film Superman'i biraz tanıtan bir film olduğundan ötürü her şeyden çok konulmamış; aynı kriptonitin çok kullanılmaması gibi dünyayı ele geçirme senaryosunun da üzerinde, detay olarak çok düşünülmemiş. Bu durum filmi kötü bir film yapıyor mu? Bence kesinlikle hayır. Benim gözümde hatta eksik denilebilecek tek ufak nokta burası olmuş. Bu senaryonun daha derinleşmesi ve Superman'in dünyadaki halkın sevgisini kazanıp onlarla kader birliği yapması durumunda zaten film bir Dark Knight seviyesine gelir.

Oyunculara geleyim önce. Fragmanı izlediğim zaman kim bu adam demiştim açıkçası. Henry Cavill rolüne tam gitmiş, adam net bir Superman yahu (alnında saçının kıvrılmamış olmasını saymazsak :). Bence oyunculukla aynı seviyede olan şey varsa, o kıyafeti vücuduyla doldurmaktır kesinlikle. Adamda çok başarılı bir vücut var. İleri derecede oyunculuk gerektirecek filmler için belki erken fakat vücut isteyen ne bileyim süper kahraman, kötü adam rollerinde kendisini artık görebileceğiz gibi geliyor. Lois Lane'imiz ise, rolüme çok gitmiş olan Amy Adams. Zaten filmin devamının geleceği bariz. Detayları okumadım, bir kaç filmlik anlaşıldı mı falan ama bu ikilinin devam etmesi bence oldukça güzel olur.

Herkesin çok tartıştığı kıyafet kısmına gelirsek. Ben genel olarak süper kahramanların tayt giymesine karşıyım o ayrı :) ama bence kırmızı slipsiz daha bir iyi olmuş gibi kıyafet. Eski çocuksu kırmızı-mavi ikilisinden biraz daha ürkütücü, daha heybetli, daha cool duran bir kıyafet olmuş. Pelerindeki logunun olmayışını filmin sonlarına doğru fark ettim ki bu da kötü durmamış demek ki. Benim her şeyden çok logo hoşuma gitti. Yani tam bir Superman Ssi değil, biraz daha farklı formatta, daha güzel bir logo olmuş. Özetlersek kıyafetin bu hale gelmesi bence genel olarak güzel olmuş. Yani Batman serilerine de bakarsak, bugün çekilecek bir filmin, siyah üzerine sırıtan sarılarla dolu retro bir kıyafet olmasını artık kimse istemez sanırım, bu da öyle bir şey işte.

Üç boyutlu filmlerdeki, 'Aman üç boyutlu film yaptık, herşeyi derin yapalım, show yapalım' anlayışı sanırım biraz biraz yıkılıyor. Zira bu filmde de benzer bir durum vardır. Efektlerde üç boyut kararında kullanılmış. Zaten karanlık ve hızlı sahnelere sahip filmlerde tam bir işkenceye dönüşüyor bence üç boyut ki bu filmde aynı hataya düşülmemiş. IMAX ise zaten ayrı bir keyif. Binalar arasındaki dövüş sahneleri, sesler, her bir yere çarpınca kırılan, çöken betonlarda kriptondan gelenlerin gücünün yansıtılışı, gezegende filmin başında geçen sahneler, kripton gezegenini parçalanışı... Uzun bir aradan sonra, geç bir saatte gitmeme rağmen bir filmi, saatime hiç bakmadan bitirdim diyebilirim.

After Earth, World War Z ve bu film arasında kalmıştım. Biraz yorum okudum ve sanırım akıllı bir tercih yapmışım. Filmi çok beğendim. Dark Knight seviyesinde tabi ki olmasa da, çok da uzak demeyeceğim ama. Diğer filmini dört gözle bekliyor olacağım. Süper kahraman filmlerini sevenler için kaçırılmaması gereken bir film ki bazıları özellikle Superman hayranıdır, o zaman kesinlikle kaçırmayın derim. Paraya kıyıp IMAX'de izlenmesi gerekiyor. Blueray'ini de çıktığı gibi edinip bir parti de evdeki büyük ekran TV'de izlemeyi planlıyorum. Kaçırmayın derim...

( man of steel, superman, henry cavill, amy adams, kriptonit, imax )

14 Mayıs 2013 Salı

JSF Ajax Requestlerdeki Tarayıcı Geri Butonu Sorunu ve Dojo İle Çözümü

Yine JSF kodlama ve yeni bir sorun ile karşı karşıyayız :) Aslında problem tam olarak JSF ile ilgili değil. Bir web uygulaması içerisinde AJAX request gönderildiğinde, URL üzerinde herhangi bir değişiklik olmuyor ise, tarayıcılar, hash değeri değişmediği için, içinde bulunduğu sayfayı tarayıcının History stack'ine eklemiyor. Dolayısıyla siz aynı sayfanın üzerinde bir çok işlem yapsanız bile, tarayıcıdaki sayfa adresi değişmediği için geri ve ileri butonlarını kullanamıyoruz.

Bu probleme çözümler mevcut aslında. Çoğu kişi tarayıcı geri-ileri butonlarını kullanıcıya kullandırtmak yerine uygulama içerisinde kendisinin oluşturduğu geri-ileri butonlarını javascript metodları vasıtasıyla kullandırtıyor. Fakat yine de tarayıcının butonlarına bir çözüm bulunmalı ve mevcut sürece entegre edilmeli. Bu noktada, araştırıp, biraz modifiye ederek uygulamamda kullandığım bir yöntemden bahsedeceğim.

Primefaces 3.5 ve JSF 2.1 kullanarak geliştirdiğim bir uygulamada, Primefaces Datatable elemanı içerisinde yüklü bir listem var ve bir file system dizini gibi, her bir satıra tıklandığında, o satırdaki klasörün içerisine girilmesi gerekiyor. Geri ve ileri butonlarının da çalışması gerekiyor.

Bu noktada çözüm olarak dojo'nun back sınıfını kullandım. Bu kütüphane, her bir click eventi esnasında, history stack'ine bir veri kaydetmemizi sağlıyor. Bu veriyi de, geri ve ileri butonlarına tıklandığı zaman yapacağı işlemi tanımlayarak kaydediyoruz. Böylece kullanıcı geri butonuna bastığı zaman, kaydettiği parametrelerle işlem yapabiliyor.

Kodlarla özetlemek gerekirse:

myfiles.xhtml
<script>
     function HistoryState(fileid)
     {
           this.fileid = fileid;
           this.back = function() { 
                browserBck([{name: 'fileid', value: fileid}]);
           };
           this.forward = function() { 
               browserFrwrd([{name: 'fileid', value: fileid}]);
           };
           this.changeUrl = false;
       }
</script>

<script type="text/javascript"  src="js/dojo.js" djConfig="preventBackButtonFix: false"></script>
<script type="text/javascript">
     dojo.require("dojo.back");
     dojo.back.init();
     dojo.back.setInitialState(new HistoryState(null));
</script>

...<p:dataTable>... 
        <p:ajax event="rowSelect" listener="#{fileController.list()}"/> 
...</p:dataTable>

   <p:remoteCommand name="browserBck" action="{fileController.listBack()}"/> 

Yukarıdaki örnekte HistoryState adında bir nesne oluşturdum. Bu nesnede, dojo için gerekli olan back, forward ve changeUrl değişkenlerini set ettim. back değişkeni, geri butonuna tıklanınca yapılacakları, forward değişkeni ileri butonu için aynı işlemleri tanımlamamızı sağlıyor. changeUrl ise, her bir state kaydolurken dojo tarafından oluşturulan random rakamın adres satırına yazılıp yazılmamasını kontrol ediyor. HTML5 desteği olmayan tarayıcılar için bu değer true olmalı. Sayfa ilk defa render olurken ise setInitialState'i çalıştırıp işlemi başlatıyoruz. Yine aynı dosyada bulunan p:dataTable elemanının bir satırına tıklanınca server tarafında liste yenilemek için <p:ajax> kullandım:

FileController.java
public void list() {
        RequestContext rc = RequestContext.getCurrentInstance();
        rc.execute("dojo.back.addToHistory(new HistoryState('" + selectedFile.getId() + "'));");
        listByParentID(selectedFile.getId());
}

public void listBack() {
        ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext(); 
        String fileID = ec.getRequestParameterMap().get("fileid");
        listByParentID(fileID);
} 

Yukarıdaki örnekte görüldüğü gibi, her bir listeleme işleminde, client tarafındaki addToHistory metoduna, HistoryState nesnemi ,içerisinde mevcut parent id bulunacak şekilde set ediyorum.

Bu örnek çok daha basitleştirilbilirdi fakat JSF ve server side'da detaylı bir örnek bulunsun istedim.

Süreci Özetlersek:
1 - xhtml dosyasında dojo'yu initialize ettik. History'ye kaydedeceğimiz nesneyi ve back-forwad metodlarımızı belirledik
2 - Bir linke tıklayıp server tarafına bir ajax request geçtik. Server tarafındaki metodda "RequestContext.getCurrentInstance().execute()" ile client tarafındaki dojo.back.addHistory metodunu çağırdık.
3 - Tarayıcının geri butonuna bastık. Bu işlem, 1. maddede belirlediğimiz back metodunu çağırdı (client-side).
4 - <p:remoteCommand> ile, 3. maddede çağrılan metodun, server tarafındaki başka bir metodu çağırmasını sağladık.
5 - Server tarafındaki metod ise istediğimiz listelemeyi yaptı ve geri butonumuz çalışmış oldu.

İleri butonu için de, forward nesnesine gerekli fonksiyonu tanımlayarak aynı işlemleri tekrarlamamız lazım.

Not: Bu şekilde çalışabilmesi için 'js' klasörünün içerisinde;
* dojo.js
* back.js
* resources/iframe_history.html

dosyalarının bulunması gerekiyor.

( jsf, primefaces, ajax, browser back button, forward, dojo, dojo.back, dojo.hash, request, xhtml, p:remoteCommand, p:dataTable )
Kaynak: http://blog.andreaskahler.com/2009/09/managing-browser-history-for-ajax-apps.html