Halo semuanya, untuk waktu yang lama saya tidak menulis artikel tentang kehidupan proyek di hub
Consulo adalah cabang dari IntelliJ IDEA Community Edition yang memiliki dukungan untuk .NET (C #), Java
Mari kita mulai
T: Consulo UI API - apa itu?
A: Ini adalah satu set API untuk membuat UI. Bahkan, satu set antarmuka sederhana yang mengulangi berbagai komponen - Button, RadionButton, Label, dll.
T: Apa tujuan membuat set API UI lain jika sudah ada Swing (karena IDEA UI menggunakan Swing untuk menampilkan antarmuka)
A: Untuk ini, mari kita menyelidiki ide yang saya ikuti saat bekerja pada API UI Consulo. Karena saya adalah kontributor utama dan hampir satu-satunya proyek Consulo, lama kelamaan menjadi sulit bagi saya untuk mempertahankan jumlah proyek yang sekarang (sekitar 156 repositori). Ada pertanyaan tentang analisis kode massal, tetapi tidak mungkin melakukannya dalam kerangka kerja satu instance IDE pada platform Desktop , dan saya tidak ingin berlatih menggunakan plug-in dari JetBrains di mana satu proyek ide-ultimate menampung semua plugin karena sejumlah alasan.
Gagasan muncul analisis pada server web. "Analisis biasa" tidak cocok untuk saya di server web, saya ingin membuat IDE Web (setidaknya hanya baca di awal) - sementara masih memiliki semua fungsi yang sama seperti di Desktop.
Anda dapat mengatakan bahwa ini mengulangi sedikit Upsource , idenya sendiri serupa - tetapi pendekatannya sama sekali berbeda.
Dan kemudian tibalah saat - ketika idenya ada, tetapi tidak diketahui bagaimana melakukannya. Saya punya pengalaman menggunakan GWT, kerangka kerja Vaadin - Saya tidak ingin menggunakan kerangka kerja non-Jawa lainnya untuk menghasilkan JS (well, atau plain js).
Saya membutuhkan waktu satu bulan untuk meneliti hal ini. Itu adalah ujian kemampuan saya di bagian ini. Pada awalnya saya hanya menggunakan GWT - untuk informasi saya menggunakan RPC bawaan.
Ada tujuan sederhana - proyek sudah terbuka, hanya perlu menampilkan Project Tree + Editor Tabs . Dalam hal ini, semuanya harus mirip dengan versi Desktop.
Segera ada masalah dengan backend yang baru dibuat. Misalnya, menggunakan EventQueue untuk tindakan internal
Singkatnya, EventQueue, ini adalah aliran UI (AWT, Swing), hampir semua yang terkait dengan UI terjadi di dalamnya - render, memproses klik tombol, dan sebagainya.
Secara historis, di IDEA, tindakan tulis harus selalu dilakukan di utas UI.
Tindakan tulis adalah rekaman ke file, atau perubahan ke beberapa layanan (misalnya, mengganti nama modul)
Pada awalnya, masalah dengan EventQueue dapat diabaikan - tetapi kemudian muncul masalah lain. Misalnya, ikon dangkal. Bayangkan kita memiliki pohon proyek
- [] nama proyek
- [] src
- tes []
- [] build.gradle
Dan untuk setiap file kita perlu mengunggah dan menampilkan gambar. Karena kita bekerja di dalam kode Swing, kita menggunakan kelas javax.swing.Icon . Masalahnya adalah itu hanya antarmuka - yang memiliki banyak implementasi yang berbeda
- ikon gambar adalah ikon yang hanya membungkus Gambar (yaitu, gambar biasa dari sistem file)
- ikon layred ikon layered yang terdiri dari dua atau lebih ikon yang ditumpuk satu sama lain
- ikon dinonaktifkan - ikon dengan filter abu-abu diterapkan
- ikon transparan - ikon dengan transparansi yang ditentukan
- dan banyak lainnya
Akibatnya, untuk menampilkan ikon di browser, Anda harus mendukung seluruh kebun binatang (dan hampir semuanya sekaligus). Salah satu masalah terkait adalah bahwa ikon yang sama sekali tidak Anda ketahui untuk suatu file mungkin akan datang (misalnya, simbol digambar piksel demi piksel di dalam beberapa plugin) - dan semacamnya perlu diabaikan.
Dengan metode kruk (baik, di mana tanpa mereka) - keputusan dibuat. Itu basi untuk memeriksa instanceof untuk jenis yang kita butuhkan - dan mengabaikan semua yang lain.
Setelah beberapa saat, dukungan dibuat untuk menavigasi sistem file, membuka file, penyorotan sintaksis, analisis semantik, info dokumen cepat, navigasi untuk referensi kode (kombinasi seperti Ctrl + B, atau Ctrl + MouseClick1 didukung). Intinya, Editor sangat mirip dengan platform Desktop.
Seperti apa itu:

Jadi - untuk membuat antarmuka web dimungkinkan dengan kekuatan saya. Tapi itu pekerjaan yang sangat kasar - yang harus diulang. Dan kemudian Vaadin datang untuk menyelamatkan.
Saya memutuskan untuk mengulang implementasi GWT saya untuk menggunakan kerangka kerja Vaadin. Tes ini ternyata sangat buruk (kinerjanya sangat menurun) - pengalaman saya menggunakan Vaadin lebih memengaruhinya, dan saya menolak opsi ini (saya bahkan melakukan pengaturan ulang pada brunch saat ini untuk melupakannya: D).
Tetapi pengalaman menggunakan Vaadin berguna bagi saya sepanjang waktu, muncul ide - untuk menyatukan UI sehingga Anda dapat menulis satu kode, tetapi mendapatkan hasil yang berbeda di output, tergantung pada platform.
Alasan lain untuk menyatukan UI adalah kebun binatang lengkap komponen Swing di dalam platform IntelliJ. Contoh dari masalah seperti itu adalah dua implementasi Tab yang sama sekali berbeda.


Pisahkan logika UI:
- frontend - satu set antarmuka untuk setiap elemen, misalnya consulo.ui.Tombol # create ()
- backend - implementasi tergantung platform
- Swing - implementasi desktop
- WGWT - implementasi web
Apa itu WGWT ? Akronim untuk Wrapper GWT. Ini adalah kerangka kerja yang ditulis sendiri - yang menyimpan STATE komponen dan mengirimkannya melalui WebSocket ke browser (yang pada gilirannya menghasilkan html). Dia menulis dengan mata pada Vaadin (ya ya - kruk lain).
Waktu berlalu - dan saya sudah bisa meluncurkan UI uji yang berfungsi sama di Desktop dan di browser

Saya juga menggunakan Vaadin yang bekerja secara paralel, karena ini adalah salah satu opsi termurah untuk membangun UI Web jika Anda menggunakan Java. Saya semakin mempelajari Vaadin - dan saya memutuskan untuk menulis ulang WGWT menjadi Vaadin lagi, tetapi dengan beberapa koreksi.
Apa yang diedit:
- penolakan untuk menggunakan hampir semua komponen Vaadin. Ada beberapa alasan - salah satunya adalah komponen yang terlalu terbatas (kustomisasi minimal).
- menggunakan komponen yang ada dari kerangka kerja WGWT saya; yaitu implementasi GWT mereka
- ada juga tambalan yang memungkinkan Anda untuk menulis anotasi Connect tanpa tautan langsung ke komponen server (ini dilakukan lebih untuk struktur proyek, untuk menghindari ketersediaan kelas server di dalam kode klien)
Hasilnya, ternyata seperti ini:
- frontend - satu set antarmuka untuk setiap elemen, misalnya consulo.ui.Tombol # create ()
- backend - implementasi saat ini tergantung pada platform
- Swing - implementasi desktop
- Vaadin - implementasi web
- Android? - agar ponsel terbakar pada awal aplikasi: D Sejauh ini, hanya pada tingkat gagasan bahwa akan mungkin untuk menggunakan kode yang ada untuk mentransfer ke Android (karena tidak akan ada ikatan dengan Swing)
Dan jadi API UI Consulo saat ini lahir.
Di mana Consulo UI API akan digunakan?
- Di semua plugin. AWT / Swing akan "diblokir" (tidak ada lagi java.awt.Color ) selama kompilasi (prosesor javac akan dibuat - nanti, mungkin tidak diperlukan sama sekali dengan kedatangan java 9). Set komponen Anda bukan obat mujarab, saya mengerti itu. Saat ini, Anda dapat membuat komponen UI kustom Anda sendiri, sejauh ini hanya di sisi Swing (dan dalam kasus seperti itu akan perlu untuk menambahkan ketergantungan pada plugin consulo.destop untuk menghindari masalah pada server web). Belum ada pembuatan komponen Vaadin di sisi plugin - akan, ini adalah tugas kecil.
- Di sisi platform, ini adalah Pengaturan / Preferensi, Jalankan Konfigurasi, Editor - pada dasarnya seluruh antarmuka yang menuju JFrame.
Apa masalahnya?
- Benar-benar tidak kompatibel dengan kode AWT / Swing (ada kelas kruk TargetAWT / TargetVaadin yang memiliki metode untuk mengkonversi komponen, tetapi kelas-kelas ini tidak dapat diakses untuk plugin).
Semua komponen Swing tidak dapat ditampilkan di browser - sebagai akibatnya, Anda perlu menulis ulang semua kode ini.
Hampir di mana-mana, API UI Consulo sudah didukung di dalam platform - ini memungkinkan Anda untuk sudah menggunakan kerangka UI baru di dalam plugin dan tidak hanya. - Keterikatan platform IntelliJ yang sangat kuat pada Swing, itu terkubur begitu dalam sehingga tanpa kruk "selanjutnya", Anda tidak bisa menggali itu (
)
Setelah beberapa waktu
Kode ini berfungsi sama di kedua platform.
Karyanya di Desktop:

Karyanya di browser:

Mengenai masalah di atas:
- Ikon. Kelas consulo.ui.image.Image diperkenalkan, yang merupakan gambar dari sistem file (dan tidak hanya). Anda dapat menggunakan metode consulo.ui.image.Image # create (java.net.URL) untuk mengunggah gambar.
Pada platform Desktop - ikon dimuat seperti yang dimuat sebelumnya, hanya sekarang jenis kembali adalah SwingImageRef (nama kelas warisan - sebelumnya consulo.ui.image.Image disebut consulo.ui.ImageRef) - antarmuka yang mewarisi javax.swing.Icon dan consulo.ui Gambar. Gambar. Nanti antarmuka ini akan dihapus (keberadaannya disebabkan oleh migrasi yang disederhanakan ke tipe baru)
Pada platform Web - URL disimpan di dalam objek, dan merupakan pengidentifikasi untuk tampilan di antarmuka (melalui URL - / app / uiImage = URLhashCode )
Kelas ImageEffects telah diperkenalkan. Dalam dirinya sendiri terdapat metode yang diperlukan untuk membuat ikon turunan. Misalnya, #grayed (Gambar) akan mengembalikan ikon dengan filter abu-abu, #transparent (Gambar) ikon tembus.
Artinya, seluruh seluruh kebun binatang yang dijelaskan di atas didorong ke bingkai sempit.
Dukungan untuk rendering elemen secara manual (yah, di mana tanpa ini) juga akan diperkenalkan. Metode ImageEffects # canvas (int height, int int, Consumer <Canvas2D> painterConsumer) akan mengembalikan ikon yang akan ditarik melalui Canvas2D
Di Desktop - bungkus akan digunakan di atas Graphics2D biasa dari Swing
Di Web - setiap panggilan ke metode Canvas2D akan disimpan, dan kemudian akan ditransfer ke browser tempat kanvas internal dari browser akan digunakan
- Tulis Aksi di Thread UI. Oooo Belum ada solusi untuk masalah ini. Saat ini - ada prototipe Write Action di Own Thread tetapi sejauh ini hanya pada platform Web, terlalu banyak yang perlu diubah di dalam platform untuk "roll it out" di Desktop.
- UI telah disatukan - tidak ada kebun binatang untuk elemen sederhana
Masalah baru juga muncul - Dialog dialog memblokir utas eksekusi selama pertunjukan. Akibatnya, IDEA suka menulis kode dalam formulir ini:
DialogWrapper wrapper = ...; int value = wrapper.showAndGet(); if(value == DialogWrapper.OK) { ... }
Pada saat yang sama, menampilkan dialog di Vaadin tidak memblokir utas eksekusi.
Untuk menghindari kebingungan dengan tampilan dialog yang sinkron dan tidak sinkron, opsi asinkron dipilih (kode di atas harus dipikirkan ulang dan diulang).
Ringkasan
Setelah beberapa saat, saya memiliki prototipe aplikasi Web yang berfungsi.

Sejauh ini ini adalah prototipe yang bergerak menuju rilis - tetapi tidak akan cepat (sayangnya).