diff --git a/build/jam/BuildSetup b/build/jam/BuildSetup index fe3340f53f..4c612b0d9a 100644 --- a/build/jam/BuildSetup +++ b/build/jam/BuildSetup @@ -131,14 +131,12 @@ if $(HAIKU_USE_GCC_PIPE) = 1 { # results in some broken code. # TODO: remove the -fno-strict-aliasing option when all code has been # analyzed/fixed with regard to aliasing. -# TODO: retest/remove the -fno-tree-vrp option as soon as we have updated our -# gcc4 compiler. if $(HAIKU_GCC_VERSION[1]) >= 3 { - HAIKU_GCC_BASE_FLAGS += -fno-strict-aliasing -fno-tree-vrp ; + HAIKU_GCC_BASE_FLAGS += -fno-strict-aliasing ; } if $(HOST_GCC_VERSION[1]) >= 3 { - HOST_GCC_BASE_FLAGS += -fno-strict-aliasing -fno-tree-vrp ; + HOST_GCC_BASE_FLAGS += -fno-strict-aliasing ; } # override gcc 2.95.3's header directory -- strictly necessary only when using diff --git a/build/jam/HaikuImage b/build/jam/HaikuImage index fade9a3075..6dbb81f3d2 100644 --- a/build/jam/HaikuImage +++ b/build/jam/HaikuImage @@ -18,7 +18,7 @@ SYSTEM_BIN = [ FFilterByBuildFeatures hd head hey hostname id ident ifconfig install installsound iroster isvolume ideinfo@ide idestatus@ide - join kernel_debugger keymap kill + join kernel_debugger keymap keystore kill less lessecho lesskey link linkcatkeys listarea listattr listimage listdev listport listres listsem listusb ln locale locate logger login logname ls lsindex @@ -84,7 +84,7 @@ PRIVATE_SYSTEM_LIBS = [ FFilterByBuildFeatures libilmimf.so ] ; SYSTEM_SERVERS = [ FFilterByBuildFeatures - app_server cddb_daemon debug_server input_server mail_daemon + app_server cddb_daemon debug_server input_server keystore_server mail_daemon media_addon_server media_server midi_server mount_server net_server notification_server power_daemon print_server print_addon_server registrar syslog_daemon diff --git a/data/artwork/icons/App_ResourceEdit b/data/artwork/icons/App_ResourceEdit new file mode 100644 index 0000000000..e35ff651ff Binary files /dev/null and b/data/artwork/icons/App_ResourceEdit differ diff --git a/data/catalogs/add-ons/disk_systems/intel/fi.catkeys b/data/catalogs/add-ons/disk_systems/intel/fi.catkeys index 35c09615fd..2c731a804c 100644 --- a/data/catalogs/add-ons/disk_systems/intel/fi.catkeys +++ b/data/catalogs/add-ons/disk_systems/intel/fi.catkeys @@ -1,2 +1,2 @@ -1 finnish x-vnd.Haiku-IntelDiskAddOn 4191422532 -Active partition BFS_Creation_Parameter Aktivoi osio +1 finnish x-vnd.Haiku-IntelDiskAddOn 946918966 +Active partition PrimaryPartitionEditor Aktivoi osio diff --git a/data/catalogs/add-ons/disk_systems/ntfs/fi.catkeys b/data/catalogs/add-ons/disk_systems/ntfs/fi.catkeys new file mode 100644 index 0000000000..23e9dc74a1 --- /dev/null +++ b/data/catalogs/add-ons/disk_systems/ntfs/fi.catkeys @@ -0,0 +1,2 @@ +1 finnish x-vnd.Haiku-NTFSDiskAddOn 25755486 +Name: NTFS_Initialize_Parameter Nimi: diff --git a/data/catalogs/add-ons/media/media-add-ons/multi_audio/fi.catkeys b/data/catalogs/add-ons/media/media-add-ons/multi_audio/fi.catkeys new file mode 100644 index 0000000000..1f4e2fb05d --- /dev/null +++ b/data/catalogs/add-ons/media/media-add-ons/multi_audio/fi.catkeys @@ -0,0 +1,34 @@ +1 finnish x-vnd.Haiku-hmulti_audio.media_addon 451057402 +Master MultiAudio Alkuperäisversio +SPDIF MultiAudio SPDIF +Gain MultiAudio Vahvistus +Output 3D center MultiAudio Tulosta 3D-keskus +Extended Setup MultiAudio Laajennettu asetus +CD MultiAudio CD +Tone control MultiAudio Äänensävyn säätö +Phone MultiAudio Puhelin +Aux MultiAudio Aux +Output bass MultiAudio Basso-ulostulo +Headphones MultiAudio Kuulokkeet +Beep MultiAudio Piip +Output mono mix MultiAudio Monomiksaus-ulostulo +Output stereo mix MultiAudio Stereomiksaus-ulostulo +Input MultiAudio Tulo +Output treble MultiAudio Diskantti-ulostulo +Mono mix MultiAudio Monomiksaus +General MultiAudio Yleisasetukset +Input & Output MultiAudio Tulot ja lähdöt +Enhanced Setup MultiAudio Laajennetut asetukset +Stereo mix MultiAudio Stereomiksaus +Output 3D depth MultiAudio Tulosta 3D-syvyys +Volume MultiAudio Äänenvoimakkuus +Output MultiAudio Lähtö +Video MultiAudio Video +Line MultiAudio Linja +Mic MultiAudio Mikrofoni + frequency: MultiAudio taajuus: +Enable MultiAudio Käytössä +Mute MultiAudio Vaimennettu +Wave MultiAudio Aalto +Setup MultiAudio Asetukset +Level MultiAudio Taso diff --git a/data/catalogs/apps/drivesetup/de.catkeys b/data/catalogs/apps/drivesetup/de.catkeys index c190fb327c..0626b1f558 100644 --- a/data/catalogs/apps/drivesetup/de.catkeys +++ b/data/catalogs/apps/drivesetup/de.catkeys @@ -1,4 +1,4 @@ -1 german x-vnd.Haiku-DriveSetup 3977871021 +1 german x-vnd.Haiku-DriveSetup 3775412465 DriveSetup System name Datenträgerverwaltung Cancel AbstractParametersPanel Abbrechen Delete MainWindow Löschen @@ -63,6 +63,7 @@ Continue MainWindow Weiter Cannot delete the selected partition. MainWindow Gewählte Partition konnte nicht gelöscht werden. Mount all MainWindow Alle einhängen End: %s Support Ende: %s +The panel could not return successfully. MainWindow Das Fenster meldete sich nicht mehr zurück. Cancel MainWindow Abbrechen Delete partition MainWindow Partition löschen Are you sure you want to change parameters of the selected partition?\n\nThe partition may no longer be recognized by other operating systems anymore! MainWindow Sollen die Parameter der ausgewählten Partition wirklich geändert werden?\n\nAndere Betriebssysteme können die Partition unter Umständen nicht mehr erkennen! diff --git a/data/catalogs/apps/drivesetup/fi.catkeys b/data/catalogs/apps/drivesetup/fi.catkeys index f82947717e..550de47576 100644 --- a/data/catalogs/apps/drivesetup/fi.catkeys +++ b/data/catalogs/apps/drivesetup/fi.catkeys @@ -1,11 +1,14 @@ -1 finnish x-vnd.Haiku-DriveSetup 644135944 +1 finnish x-vnd.Haiku-DriveSetup 3775412465 DriveSetup System name Levyasema-asetukset +Cancel AbstractParametersPanel Peru Delete MainWindow Poista Are you sure you want to write the changes back to disk now?\n\nAll data on the selected partition will be irretrievably lost if you do so! MainWindow Oletko varma, että haluat nyt kirjoittaa muutokset takaisin levylle?\n\nKaikki valitun osion tiedot katoavat palauttamattomasti, jos teet niin! Rescan MainWindow Etsi uudelleen OK MainWindow Valmis Could not aquire partitioning information. MainWindow Ei voitu hakea osiointitietoja. There's no space on the partition where a child partition could be created. MainWindow Osiolla ei ole mitään tilaa, johon olisi voitu luoda tytärosio. +Initialize InitializeParametersPanel Alusta +OK AbstractParametersPanel Valmis PartitionList Unable to find the selected partition by ID. MainWindow Valitun osion löytäminen tunnisteen perusteella epäonnistui. Select a partition from the list below. DiskView Valitse osio alapuolella olevasta luettelosta. @@ -15,6 +18,7 @@ The selected disk is read-only. MainWindow Valittu levy on kirjoitussuojattu. Are you sure you want to format the partition \"%s\"? You will be asked again before changes are written to the disk. MainWindow Oletko varma, että haluat alustaa osion \"%s\"? Samaa kysytään uudelleen ennen muutosten kirjoittamista levylle. Could not mount partition %s. MainWindow Osion %s liittäminen epäonnistui. The partition %s has been successfully formatted.\n MainWindow Osion %s alustus onnistui.\n +Change parameters MainWindow Vaihda parametreja The partition %s is already unmounted. MainWindow Osio %s on jo liitetty. Failed to delete the partition. No changes have been written to disk. MainWindow Osion poistaminen epäonnistui. Mitään muutoksia ei ole kirjoitettu levylle. Could not delete the selected partition. MainWindow Valitun osion poistaminen epäonnistui. @@ -33,38 +37,53 @@ Write changes MainWindow Kirjoita muutokset There was an error preparing the disk for modifications. MainWindow Tapahtui virhe valmisteltaessa levyä muutoksia varten. The partition %s is already mounted. MainWindow Osio %s on jo liitetty. Are you sure you want to format the partition? You will be asked again before changes are written to the disk. MainWindow Oletko varma, että haluat alustaa osion? Samaa kysytään uudelleen ennen muutosten kirjoittamista levylle. +Partition name: ChangeParametersPanel Osionimi: +Change ChangeParametersPanel Vaihda Are you sure you want to write the changes back to disk now?\n\nAll data on the disk %s will be irretrievably lost if you do so! MainWindow Oletko varma, että haluat nyt kirjoittaa muutokset takaisin levylle?\n\nKaikki levyn %s tiedot katoavat palauttamattomasti, jos teet niin! Are you sure you want to delete the selected partition?\n\nAll data on the partition will be irretrievably lost if you do so! MainWindow Oletko varma, että haluat poistaa valitun osion?\n\nKaikki osion tiedot katoavat palauttamattomasti, jos teet niin! Create… MainWindow Luo… Disk system \"%s\"\" not found! MainWindow Levyjärjestelmää ”%s” ei löytynyt! The disk has been successfully initialized.\n MainWindow Levyn alustus onnistui.\n Could not unmount partition %s. MainWindow Osion %s irrottaminen epäonnistui. +Failed to change the parameters of the partition. No changes have been written to disk. MainWindow Osion parametrien vaihtaminen epäonnistui. Levylle ei ole kirjoitettu mitään muutoksia. Failed to format the partition %s!\n MainWindow Osion %s alustus epäonnistui!\n Mount MainWindow Liitä +Partition type PartitionList Osiotyyppi Are you sure you want to format a raw disk? (most people initialize the disk with a partitioning system first) You will be asked again before changes are written to the disk. MainWindow Oletko varma, että haluat alustaa raakalevyn? (useimmat ihmiset alustavat levyn ensin osiointijärjestelmällä) Samaa kysytään uudelleen ennen kuin muutokset kirjoitetaan levylle. +The panel experienced a problem! MainWindow Paneelissa oli pulmia! +Change parameters… MainWindow Vaihda parametreja... Device PartitionList Laite Disk MainWindow Levy Are you sure you want to initialize the selected disk? All data will be lost. You will be asked again before changes are written to the disk.\n MainWindow Oletko varma, etä haluat alustaa valitun levyn? Kaikki olemassaolevat tiedot katoavat. Samaa kysytään uudelleen ennen kuin muutokset kirjoitetaan levylle.\n +Partition size CreateParametersPanel Osiokoko Device DiskView Laite Active PartitionList Aktiivinen Volume name PartitionList Taltionimi Continue MainWindow Jatka Cannot delete the selected partition. MainWindow Valitun osion poistaminen epäonnistui. Mount all MainWindow Liitä kaikki +End: %s Support Loppu: %s +The panel could not return successfully. MainWindow Paluu paneelista epäonnistui. Cancel MainWindow Peru Delete partition MainWindow Poista osio +Are you sure you want to change parameters of the selected partition?\n\nThe partition may no longer be recognized by other operating systems anymore! MainWindow Oletko varma, että haluat vaihtaa valitun osion parametreja?\n\nMuut käyttöjärjestelmät eivät ehkä enää tunnista osiota! Eject MainWindow Poista asemasta Partition MainWindow Osio +Validation of the given parameters failed. MainWindow Annettujen parametrien todentaminen epäonnistui. +Create CreateParametersPanel Luo File system PartitionList Tiedostojärjestelmä Validation of the given creation parameters failed. MainWindow Annettujen luontiparametrien todentaminen epäonnistui. +Partition type: ChangeParametersPanel Osiotyyppi: Size PartitionList Koko Wipe (not implemented) MainWindow Alustus (ei ole toteutettu) Validation of the given initialization parameters failed. MainWindow Annettujen alustusparametrien todentaminen epäonnistui. The selected partition does not contain a partitioning system. MainWindow Valittu osio ei sisällä osiointijärjestelmää. +Offset: %s Support Siirrososoite: %s Are you sure you want to write the changes back to disk now?\n\nAll data on the partition %s will be irretrievably lost if you do so! MainWindow Oletko varma, että haluat nyt kirjoittaa muutokset takaisin levylle?\n\nKaikki osion %s tiedot kadotetaan palauttamattomasti, jos teet niin! The partition %s is currently mounted. MainWindow Osio %s on nykyisin liitetty. Surface test (not implemented) MainWindow Pintatesti (ei toteutettu) Format MainWindow Alusta +Could not change the parameters of the selected partition. MainWindow Valitun osion parametrien vaihtaminen epäonnistui. Parameters PartitionList Parametrit Creation of the partition has failed. MainWindow Osion luominen epäonnistui. The currently selected partition is not empty. MainWindow Nykyinen valittu osio ei ole tyhjä. diff --git a/data/catalogs/apps/drivesetup/fr.catkeys b/data/catalogs/apps/drivesetup/fr.catkeys index 03662b085b..b459f00aeb 100644 --- a/data/catalogs/apps/drivesetup/fr.catkeys +++ b/data/catalogs/apps/drivesetup/fr.catkeys @@ -1,11 +1,14 @@ -1 french x-vnd.Haiku-DriveSetup 659039073 +1 french x-vnd.Haiku-DriveSetup 1767229522 DriveSetup System name Gestionnaire de disque +Cancel AbstractParametersPanel Annuler Delete MainWindow Supprimer Are you sure you want to write the changes back to disk now?\n\nAll data on the selected partition will be irretrievably lost if you do so! MainWindow Êtes-vous sûr de vouloir écrire les changements sur le disque ?\n\nToutes les données de la partition sélectionnée seront effacées si vous le faites ! Rescan MainWindow Analyser OK MainWindow OK Could not aquire partitioning information. MainWindow Impossible de récupérer les informations sur les partitions. There's no space on the partition where a child partition could be created. MainWindow Il n'y a pas de place dans cette partition pour créer une partition fille. +Initialize InitializeParametersPanel Initialiser +OK AbstractParametersPanel OK PartitionList Unable to find the selected partition by ID. MainWindow Impossible de trouver la partition sélectionnée par son ID. Select a partition from the list below. DiskView Sélectionnez une partition dans la liste ci-dessous. diff --git a/data/catalogs/apps/firstbootprompt/fi.catkeys b/data/catalogs/apps/firstbootprompt/fi.catkeys index ab081ab1dc..201ee87863 100644 --- a/data/catalogs/apps/firstbootprompt/fi.catkeys +++ b/data/catalogs/apps/firstbootprompt/fi.catkeys @@ -1,5 +1,6 @@ -1 finnish x-vnd.Haiku-FirstBootPrompt 988630706 +1 finnish x-vnd.Haiku-FirstBootPrompt 2649051796 Custom BootPromptWindow Oma +Boot to Desktop BootPromptWindow Alkukäynnistä työpöydälle Thank you for trying out Haiku! We hope you'll like it!\n\nYou can select your preferred language and keyboard layout from the list on the left which will then be used instantly. You can easily change both settings from the Desktop later on on the fly.\n\nDo you wish to run the Installer or continue booting to the Desktop?\n BootPromptWindow For other languages, a note could be added: \"Note: Localization of Haiku applications and other components is an on-going effort. You will frequently encounter untranslated strings, but if you like, you can join in the work at .\" Kiitoksia siitä, että kokeilet Haikua! Toivomme, että pidät siitä!\n\nVoit valita ensisijaisen kielen ja näppäimistöasetuksen vasemmalla näkyvästä luettelosta. Asetukset otetaan käyttöön välittömästi. Voit helposti vaihtaa molempia asetuksia myöhemmin työpöydältäsi.\n\nHaluatko suorittaa asennusohjelman tai jatkaa alkulautausta työpöydälle?\n Huomaa: Ponnistelemme edelleen Haiku-sovellusten ja muiden komponenttien kotoistamiseksi. Kohtaat usein suomentamattomia merkkijonoja, mutta jos haluat, voit liittyä työhön osoitteessa . Language BootPromptWindow Kieli Welcome to Haiku! BootPromptWindow Tervetuloa Haikuun! diff --git a/data/catalogs/apps/fontdemo/fi.catkeys b/data/catalogs/apps/fontdemo/fi.catkeys index 1db9f835ca..0de04588ca 100644 --- a/data/catalogs/apps/fontdemo/fi.catkeys +++ b/data/catalogs/apps/fontdemo/fi.catkeys @@ -1,4 +1,4 @@ -1 finnish x-vnd.Haiku-FontDemo 1300625863 +1 finnish x-vnd.Haiku-FontDemo 3522850500 Outline: ControlView Ääriviiva: Size: 50 ControlView Koko: 50 Stop cycling ControlView Lopeta kierros @@ -14,6 +14,7 @@ Rotation: 0 ControlView Kierto: 0 Drawing mode: ControlView Piirrostila: Haiku, Inc. ControlView Haiku, Inc. Controls FontDemo Ohjaimet +FontDemo System name FontDemo Outline: %d ControlView Ääriviiva: %d Text: ControlView Teksti: Antialiased text ControlView Peitenimetön teksti diff --git a/data/catalogs/apps/launchbox/de.catkeys b/data/catalogs/apps/launchbox/de.catkeys index 574dd880a6..89412eb866 100644 --- a/data/catalogs/apps/launchbox/de.catkeys +++ b/data/catalogs/apps/launchbox/de.catkeys @@ -1,4 +1,4 @@ -1 german x-vnd.Haiku-LaunchBox 3016105370 +1 german x-vnd.Haiku-LaunchBox 3692177981 New LaunchBox Neu Set description… LaunchBox Beschreibung ändern… Vertical layout LaunchBox Vertikale Anordnung @@ -6,6 +6,7 @@ OK LaunchBox OK Pad 1 LaunchBox Block 1 last chance LaunchBox letzte Chance Quit LaunchBox Beenden +Open containing folder LaunchBox Speicherort öffnen Clear button LaunchBox Feld leeren LaunchBox System name LaunchBox Ignore double-click LaunchBox Doppelklick ignorieren diff --git a/data/catalogs/apps/launchbox/hu.catkeys b/data/catalogs/apps/launchbox/hu.catkeys index 8624590250..0eab8e1a16 100644 --- a/data/catalogs/apps/launchbox/hu.catkeys +++ b/data/catalogs/apps/launchbox/hu.catkeys @@ -1,4 +1,4 @@ -1 hungarian x-vnd.Haiku-LaunchBox 3016105370 +1 hungarian x-vnd.Haiku-LaunchBox 3692177981 New LaunchBox Új Set description… LaunchBox Leírás… Vertical layout LaunchBox Függőleges elrendezés @@ -6,6 +6,7 @@ OK LaunchBox Rendben Pad 1 LaunchBox 1. tálca last chance LaunchBox utolsó esély Quit LaunchBox Kilépés +Open containing folder LaunchBox Tartalmazó mappa megnyitása Clear button LaunchBox Gomb kiürítése LaunchBox System name Indítósáv Ignore double-click LaunchBox Dupla kattintás figyelmen kívül hagyása diff --git a/data/catalogs/apps/launchbox/ja.catkeys b/data/catalogs/apps/launchbox/ja.catkeys index 136fced848..61ec830123 100644 --- a/data/catalogs/apps/launchbox/ja.catkeys +++ b/data/catalogs/apps/launchbox/ja.catkeys @@ -1,4 +1,4 @@ -1 japanese x-vnd.Haiku-LaunchBox 3016105370 +1 japanese x-vnd.Haiku-LaunchBox 3692177981 New LaunchBox 新規作成 Set description… LaunchBox 説明の作成… Vertical layout LaunchBox 垂直配置 @@ -6,6 +6,7 @@ OK LaunchBox OK Pad 1 LaunchBox パッド 1 last chance LaunchBox 最後のチャンス Quit LaunchBox 終了 +Open containing folder LaunchBox フォルダーを開く Clear button LaunchBox ボタンを消去 LaunchBox System name ランチャー Ignore double-click LaunchBox ダブルクリックを無視する diff --git a/data/catalogs/apps/launchbox/sv.catkeys b/data/catalogs/apps/launchbox/sv.catkeys index b2464136fd..a723f9e4d7 100644 --- a/data/catalogs/apps/launchbox/sv.catkeys +++ b/data/catalogs/apps/launchbox/sv.catkeys @@ -1,4 +1,4 @@ -1 swedish x-vnd.Haiku-LaunchBox 3016105370 +1 swedish x-vnd.Haiku-LaunchBox 3692177981 New LaunchBox Ny Set description… LaunchBox Ange beskrivning... Vertical layout LaunchBox Vertikal utformning @@ -6,6 +6,7 @@ OK LaunchBox OK Pad 1 LaunchBox Block 1 last chance LaunchBox sista chansen Quit LaunchBox Avsluta +Open containing folder LaunchBox Öppna innehållande mapp Clear button LaunchBox Rensa knapp LaunchBox System name StartBlock Ignore double-click LaunchBox Ignorera dubbelklick diff --git a/data/catalogs/apps/terminal/fi.catkeys b/data/catalogs/apps/terminal/fi.catkeys index 8854ac9b93..bff140c840 100644 --- a/data/catalogs/apps/terminal/fi.catkeys +++ b/data/catalogs/apps/terminal/fi.catkeys @@ -1,4 +1,4 @@ -1 finnish x-vnd.Haiku-Terminal 766764238 +1 finnish x-vnd.Haiku-Terminal 2645209895 Not found. Terminal TermWindow Ei löytynyt. Switch Terminals Terminal TermWindow Vaihda pääteikkunoita Change directory Terminal TermView Vaihda hakemistoa @@ -21,6 +21,7 @@ Font: Terminal AppearancePrefView Kirjasintyyppi: Copy here Terminal TermView Kopioi tänne Really close? Terminal TermWindow Suljetaanko todella? Copy Terminal TermWindow Kopioi +Terminal Terminal TermWindow The title for the main window menubar entry related to terminal sessions Pääteikkuna Color scheme: Terminal AppearancePrefView Väriteema: Window title: Terminal TermWindow Ikkunaotsikko: Unrecognized option \"%s\"\n Terminal arguments parsing Tunnistamaton valitsin ”%s”\n @@ -61,6 +62,7 @@ Text not found. Terminal TermWindow Tekstiä ei löydy. Find… Terminal TermWindow Etsi... The process \"%1\" is still running.\nIf you close the Terminal, the process will be killed. Terminal TermWindow Prosessia ”%1” suoritetaan yhä.\nJos suljet Pääteikkunan, prosessi tapetaan. Move here Terminal TermView Siirrä tänne +\t%d\t-\tThe current working directory of the active process in the\n\t\t\tcurrent tab. Optionally the maximum number of path components\n\t\t\tcan be specified. E.g. '%2d' for at most two components.\n\t%T\t-\tThe Terminal application name for the current locale.\n\t%i\t-\tThe index of the window.\n\t%p\t-\tThe name of the active process in the current tab.\n\t%t\t-\tThe title of the current tab.\n\t%%\t-\tThe character '%'. Terminal ToolTips \t%d\t-\tAktiivin prosessin nykyinen työhakemisto on nykyisessä\n\t\t\tvälilehdessä. Valinnaisesti voidaan määritellä polkukomponenttien\n\t\t\tenimmäismäärä. Esim.: '%2d' vähintään kahdelle komponentille.\n\t%T\t-\tPääteikkunan nimi nykyisillä paikallisasetuksilla.\n\t%i\t-\tIkkunaindeksi.\n\t%p\t-\tAktiivin prosessin nimi nykyisessä välilehdessä.\n\t%t\t-\tThe title of the current tab.\n\t%%\t-\tMerkki '%'. Retro Terminal colors scheme Retro Error! Terminal getString Virhe! New tab Terminal TermWindow Uusi välilehti diff --git a/data/catalogs/apps/terminal/pl.catkeys b/data/catalogs/apps/terminal/pl.catkeys index 03b377fbe1..eb7a42351a 100644 --- a/data/catalogs/apps/terminal/pl.catkeys +++ b/data/catalogs/apps/terminal/pl.catkeys @@ -1,4 +1,4 @@ -1 polish x-vnd.Haiku-Terminal 3435701556 +1 polish x-vnd.Haiku-Terminal 2997644674 Not found. Terminal TermWindow Nie znaleziono. Switch Terminals Terminal TermWindow Przełącz Terminal Change directory Terminal TermView Zmień folder @@ -21,6 +21,7 @@ Font: Terminal AppearancePrefView Czcionka: Copy here Terminal TermView Kopiuj tutaj Really close? Terminal TermWindow Na pewno zamknąć? Copy Terminal TermWindow Kopiuj +Terminal Terminal TermWindow The title for the main window menubar entry related to terminal sessions Terminal Color scheme: Terminal AppearancePrefView Schemat kolorów: Window title: Terminal TermWindow Tytuł okna: Unrecognized option \"%s\"\n Terminal arguments parsing Nieznana opcja \"%s\"\n diff --git a/data/catalogs/apps/terminal/sv.catkeys b/data/catalogs/apps/terminal/sv.catkeys index 0daa3e3a83..109c858073 100644 --- a/data/catalogs/apps/terminal/sv.catkeys +++ b/data/catalogs/apps/terminal/sv.catkeys @@ -1,4 +1,4 @@ -1 swedish x-vnd.Haiku-Terminal 328707356 +1 swedish x-vnd.Haiku-Terminal 2645209895 Not found. Terminal TermWindow Hittades ej. Switch Terminals Terminal TermWindow Växla terminal Change directory Terminal TermView Byt katalog @@ -62,6 +62,7 @@ Text not found. Terminal TermWindow Text hittades inte. Find… Terminal TermWindow Sök... The process \"%1\" is still running.\nIf you close the Terminal, the process will be killed. Terminal TermWindow Processen \"%1\" körs fortfarande.\nOm du stänger Terminalen kommer processen att termineras. Move here Terminal TermView Flytta hit +\t%d\t-\tThe current working directory of the active process in the\n\t\t\tcurrent tab. Optionally the maximum number of path components\n\t\t\tcan be specified. E.g. '%2d' for at most two components.\n\t%T\t-\tThe Terminal application name for the current locale.\n\t%i\t-\tThe index of the window.\n\t%p\t-\tThe name of the active process in the current tab.\n\t%t\t-\tThe title of the current tab.\n\t%%\t-\tThe character '%'. Terminal ToolTips \t%d\t-\t Arbetskatalogen till den aktiva processen på den valda tabben\n\t\t\t eller de maximala antal sökvägs komponenter kan bli specificerade.\n\t\t\t E.g. '%2d' för att ange två komponenter.\n\t%T\t-\tTerminal applikationsnamnet för denna översättning.\n\t%i\t-\t Indexet för detta fönster.\n\t%p\t-\tNamnet på den aktiva processen io den valda tabben.\n\t%t\t-\tNamnet på den valda tabben.\n\t%%\t-\t Tecknet '%'. Retro Terminal colors scheme Retro Error! Terminal getString Fel! New tab Terminal TermWindow Ny flik diff --git a/data/catalogs/apps/webpositive/de.catkeys b/data/catalogs/apps/webpositive/de.catkeys index 634635f628..0b35527229 100644 --- a/data/catalogs/apps/webpositive/de.catkeys +++ b/data/catalogs/apps/webpositive/de.catkeys @@ -1,4 +1,4 @@ -1 german x-vnd.Haiku-WebPositive 233049275 +1 german x-vnd.Haiku-WebPositive 3577331897 Show home button Settings Window Home-Symbol anzeigen Username: Authentication Panel Benutzername: Copy URL to clipboard Download Window Adresse kopieren @@ -16,6 +16,7 @@ Start page: Settings Window Startseite: History WebPositive Window Verlauf Error opening downloads folder Download Window Fehler beim Öffnen des Download-Ordners Paste WebPositive Window Einfügen +Proxy username: Settings Window Proxy-Nutzername: Settings Settings Window Einstellungen %seconds seconds left Download Window Noch %seconds Sekunden Confirmation WebPositive Window Bestätigung @@ -41,6 +42,7 @@ Quit WebPositive Window Beenden Full screen WebPositive Window Vollbild Open download error Download Window Fehler beim Öffnen Standard font: Settings Window Standardschrift: +Find previous occurrence of search terms WebPositive Window find bar previous button tooltip Vorheriger Treffer Restart Download Window Neustart Proxy server Settings Window Proxy-Server Open containing folder Download Window Speicherort öffnen @@ -58,6 +60,7 @@ Cut WebPositive Window Ausschneiden Bookmark this page WebPositive Window Lesezeichen für diese Seite anlegen There was an error trying to show the Bookmarks folder.\n\nError: %error WebPositive Window Don't translate variable %error Der Lesezeichen-Ordner kann nicht angezeigt werden.\n\nFehler: %error Open downloads folder Download Window Download-Ordner öffnen +Proxy password: Settings Window Proxy-Passwort: Number of days to keep links in History menu: Settings Window Anzahl der Tage im Verlauf-Menü: Hide Download Window Ausblenden Reset size WebPositive Window Größe zurücksetzen @@ -67,6 +70,7 @@ There was an error retrieving the bookmark folder.\n\nError: %error WebPositive Over 1 day left Download Window Noch über einen Tag Downloads WebPositive Window Downloads Requesting %url WebPositive Window %url wird angefordert +Find next occurrence of search terms WebPositive Window find bar next button tooltip Nächster Treffer Apply Settings Window Anwenden Bookmark info WebPositive Window Lesezeichen Info Size: Font Selection view Größe: @@ -80,6 +84,7 @@ Open blank page Settings Window Leere Seite öffnen New tabs: Settings Window Neue Reiter: Cancel WebPositive Window Abbrechen Open all WebPositive Window Alle öffnen +Proxy server requires authentication Settings Window Der Proxy-Server verlangt eine Authentifizierung Clear URL Bar Leeren Cut URL Bar Ausschneiden Clear WebPositive Window Leeren diff --git a/data/catalogs/apps/webpositive/hu.catkeys b/data/catalogs/apps/webpositive/hu.catkeys index 26a74725e8..1d6c6f88b2 100644 --- a/data/catalogs/apps/webpositive/hu.catkeys +++ b/data/catalogs/apps/webpositive/hu.catkeys @@ -1,4 +1,4 @@ -1 hungarian x-vnd.Haiku-WebPositive 233049275 +1 hungarian x-vnd.Haiku-WebPositive 3577331897 Show home button Settings Window Kezdőlap-gomb megjelenítése Username: Authentication Panel Felhasználónév: Copy URL to clipboard Download Window Cím másolása a vágólapra @@ -16,6 +16,7 @@ Start page: Settings Window Kezdőlap: History WebPositive Window Előzmény Error opening downloads folder Download Window Hiba történt a letöltések mappa megnyitásakor Paste WebPositive Window Beillesztés +Proxy username: Settings Window Felhasználónév a proxyhoz: Settings Settings Window Beállítások %seconds seconds left Download Window %seconds másodperc van hátra Confirmation WebPositive Window Megerősítés @@ -41,6 +42,7 @@ Quit WebPositive Window Kilépés Full screen WebPositive Window Teljes képernyő Open download error Download Window A letöltés nem nyitható meg Standard font: Settings Window Normál betűtípus: +Find previous occurrence of search terms WebPositive Window find bar previous button tooltip Előző találat Restart Download Window Újraindítás Proxy server Settings Window Proxy Open containing folder Download Window Tartalmazó mappa megnyitása @@ -58,6 +60,7 @@ Cut WebPositive Window Kivágás Bookmark this page WebPositive Window Könyvjelző az oldalhoz There was an error trying to show the Bookmarks folder.\n\nError: %error WebPositive Window Don't translate variable %error Hiba történt a Könyvjelzők mappa megjelenítésekor.\n\nHiba: %error Open downloads folder Download Window A letöltési mappa megnyitása +Proxy password: Settings Window Jelszó a proxyhoz: Number of days to keep links in History menu: Settings Window Előzmények megtartásának ideje (nap): Hide Download Window Elrejtés Reset size WebPositive Window Méret visszaállítása @@ -67,6 +70,7 @@ There was an error retrieving the bookmark folder.\n\nError: %error WebPositive Over 1 day left Download Window Több, mint 1 nap van hátra Downloads WebPositive Window Letöltések Requesting %url WebPositive Window %url megnyitása +Find next occurrence of search terms WebPositive Window find bar next button tooltip Következő találat Apply Settings Window Alkalmaz Bookmark info WebPositive Window Könyvjelző információi Size: Font Selection view Méret: @@ -80,6 +84,7 @@ Open blank page Settings Window Üres oldal megnyitása New tabs: Settings Window Új fülek: Cancel WebPositive Window Mégse Open all WebPositive Window Az összes megnyitása +Proxy server requires authentication Settings Window A proxy hitelesítést kér Clear URL Bar Törlés Cut URL Bar Kivágás Clear WebPositive Window Törlés diff --git a/data/catalogs/apps/webpositive/ja.catkeys b/data/catalogs/apps/webpositive/ja.catkeys index bd247f7e8d..66881f1190 100644 --- a/data/catalogs/apps/webpositive/ja.catkeys +++ b/data/catalogs/apps/webpositive/ja.catkeys @@ -1,4 +1,4 @@ -1 japanese x-vnd.Haiku-WebPositive 233049275 +1 japanese x-vnd.Haiku-WebPositive 3577331897 Show home button Settings Window ホームボタンを表示する Username: Authentication Panel ユーザー名: Copy URL to clipboard Download Window URL をクリップボードにコピー @@ -16,6 +16,7 @@ Start page: Settings Window スタートページ: History WebPositive Window 履歴 Error opening downloads folder Download Window ダウンロードフォルダーを開く際にエラーが発生しました Paste WebPositive Window 貼り付け +Proxy username: Settings Window ユーザー名: Settings Settings Window 設定 %seconds seconds left Download Window 残り %seconds 秒 Confirmation WebPositive Window 確認 @@ -41,6 +42,7 @@ Quit WebPositive Window 終了 Full screen WebPositive Window 全画面表示 Open download error Download Window ダウンロードを開く際にエラー Standard font: Settings Window 標準フォント: +Find previous occurrence of search terms WebPositive Window find bar previous button tooltip 文字列を前方へ検索 Restart Download Window 再開 Proxy server Settings Window プロキシサーバー Open containing folder Download Window ファイルのフォルダーを開く @@ -48,38 +50,41 @@ New window WebPositive Window 新規ウィンドウ Open Download Window 開く Reload WebPositive Window 再読み込み Downloads Download Window ダウンロード -Sans serif font: Settings Window サンセリフフォント: +Sans serif font: Settings Window サンセリフフォント: Over %days days left Download Window 残り %days 日以上 Forward WebPositive Window 進む of Download Window ...as in '12kB of 256kB' / Revert Settings Window 元に戻す -Fixed font: Settings Window 固定幅フォント: +Fixed font: Settings Window 固定幅フォント: Cut WebPositive Window 切り取り Bookmark this page WebPositive Window このページをブックマーク There was an error trying to show the Bookmarks folder.\n\nError: %error WebPositive Window Don't translate variable %error ブックマークフォルダーを表示しようとした時にエラーが発生しました。\n\nエラー: %error Open downloads folder Download Window ダウンロードフォルダーを開く -Number of days to keep links in History menu: Settings Window 履歴メニューにリンクを残す日数: +Proxy password: Settings Window パスワード: +Number of days to keep links in History menu: Settings Window 履歴メニューにリンクを残す日数: Hide Download Window 隠す Reset size WebPositive Window サイズをリセット -Find: WebPositive Window 検索: +Find: WebPositive Window 検索: Increase size WebPositive Window サイズを大きく -There was an error retrieving the bookmark folder.\n\nError: %error WebPositive Window Don't translate the variable %error ブックマークフォルダーの取得時にエラーが発生しました。\n\nエラー: %error +There was an error retrieving the bookmark folder.\n\nError: %error WebPositive Window Don't translate the variable %error ブックマークフォルダーの取得時にエラーが発生しました。\n\nエラー: %error Over 1 day left Download Window 残り 1 日以上 Downloads WebPositive Window ダウンロード Requesting %url WebPositive Window 要求中 %url +Find next occurrence of search terms WebPositive Window find bar next button tooltip 文字列を後方へ検索 Apply Settings Window 適用 Bookmark info WebPositive Window ブックマーク情報 -Size: Font Selection view サイズ: +Size: Font Selection view サイズ: Show tabs if only one page is open Settings Window ページが一つだけ開いている場合もタブを表示する。 About WebPositive Window WebPositive について -Finish: Download Window Finishing time 完了: +Finish: Download Window Finishing time 完了: Fonts Settings Window フォント OK Download Window OK Page source error WebPositive Window ページソースのエラー Open blank page Settings Window 空白のページを開く -New tabs: Settings Window 新しいタブ: +New tabs: Settings Window 新しいタブ: Cancel WebPositive Window 中止 Open all WebPositive Window すべて開く +Proxy server requires authentication Settings Window プロキシサーバーは認証を必要 Clear URL Bar クリア Cut URL Bar 切り取り Clear WebPositive Window クリア @@ -87,8 +92,8 @@ Remove Download Window 削除 Find WebPositive Window 検索 Find previous WebPositive Window 前を検索 Settings WebPositive Window 設定 -Proxy server address: Settings Window プロキシサーバーのアドレス: -Proxy server port: Settings Window プロキシサーバーポート: +Proxy server address: Settings Window プロキシサーバーのアドレス: +Proxy server port: Settings Window プロキシサーバーポート: Bookmarks WebPositive Window ブックマーク %minutes minutes Download Window %minutes 分 Paste URL Bar 貼り付け @@ -100,7 +105,7 @@ Open start page Settings Window スタートページを開く Continue downloads WebPositive ダウンロードを続ける Cancel Download Window 中止 Open search page Settings Window 検索ページを開く -Password: Authentication Panel パスワード: +Password: Authentication Panel パスワード: Back WebPositive Window 戻る New browser window Download Window 新規ブラウザウィンドウ Today WebPositive Window 今日 @@ -108,17 +113,17 @@ Today WebPositive Window 今日 Remember username and password for this site Authentication Panel このサイトのユーザー名とパスワードを記憶する Earlier WebPositive Window 6 日以上前 Authentication required Authentication Panel 認証が必要です -Use proxy server to connect to the internet Settings Window インターネット接続にプロキシーサーバーを使用する。 +Use proxy server to connect to the internet Settings Window インターネット接続にプロキシサーバーを使用する。 There are still downloads in progress, do you really want to quit WebPositive now? WebPositive ダウンロードが進行中です。WebPositive を今終了してもよいですか? Auto-hide interface in full screen mode Settings Window 全画面表示時に自動的にインターフェイスを隠す。 %url failed WebPositive Window Loading URL failed. Don't translate variable %url. %url 失敗。 New tab WebPositive Window 新規タブ Downloads in progress WebPositive ダウンロードが進行中です -Style: Font Selection view スタイル: +Style: Font Selection view スタイル: General Settings Window 一般 View WebPositive Window 表示 Previous WebPositive Window 前へ -There was an error creating the bookmark file.\n\nError: %error WebPositive Window Don't translate variable %error ブックマークファイルの作成中にエラーが発生しました。\n\nエラー: %error +There was an error creating the bookmark file.\n\nError: %error WebPositive Window Don't translate variable %error ブックマークファイルの作成中にエラーが発生しました。\n\nエラー: %error Bookmark error WebPositive Window ブックマークエラー Do you really want to clear the browsing history? WebPositive Window 本当にブラウズ履歴をクリアしますか? Copy WebPositive Window コピー @@ -131,6 +136,6 @@ Copy URL Bar コピー OK WebPositive Window OK Manage bookmarks WebPositive Window ブックマークの管理 A bookmark for this page (%bookmarkName) already exists. WebPositive Window Don't translate variable %bookmarkName このページ (%bookmarkName) のブックマークはすでにあります。 -New windows: Settings Window 新規ウィンドウ: +New windows: Settings Window 新規ウィンドウ: %url finished WebPositive Window Loading URL finished. Don't translate variable %url. %url 完了。 Remove finished Download Window Remove finished diff --git a/data/catalogs/apps/webpositive/sv.catkeys b/data/catalogs/apps/webpositive/sv.catkeys index ce2d8d97ec..6d084cf973 100644 --- a/data/catalogs/apps/webpositive/sv.catkeys +++ b/data/catalogs/apps/webpositive/sv.catkeys @@ -1,4 +1,4 @@ -1 swedish x-vnd.Haiku-WebPositive 233049275 +1 swedish x-vnd.Haiku-WebPositive 3577331897 Show home button Settings Window Visa hem-knappen Username: Authentication Panel Användarnamn: Copy URL to clipboard Download Window Kopiera URL till urklipp @@ -16,6 +16,7 @@ Start page: Settings Window Start sida: History WebPositive Window Historik Error opening downloads folder Download Window Fel vid öppnande av nerladdnings foldern Paste WebPositive Window Klistra in +Proxy username: Settings Window Proxyanvändarnamn: Settings Settings Window Inställningar %seconds seconds left Download Window %seconds secunder kvar Confirmation WebPositive Window Bekräftelse @@ -41,6 +42,7 @@ Quit WebPositive Window Avsluta Full screen WebPositive Window Helskärm Open download error Download Window Öppna nerladdnings error Standard font: Settings Window Standardtypsnitt: +Find previous occurrence of search terms WebPositive Window find bar previous button tooltip Sök föregående förekomst av söktermerna Restart Download Window Starta om Proxy server Settings Window Proxyserver Open containing folder Download Window Öppna innehållande mapp @@ -58,6 +60,7 @@ Cut WebPositive Window Klipp ut Bookmark this page WebPositive Window Spara sidan som bokmärke There was an error trying to show the Bookmarks folder.\n\nError: %error WebPositive Window Don't translate variable %error Problem att visa Bokmärkes mappen.\n\nFel: %error Open downloads folder Download Window Öppna nerladdningsmapp +Proxy password: Settings Window Proxylösenord: Number of days to keep links in History menu: Settings Window Antal dagar att bevara länkar i Historia menyn: Hide Download Window Dölj Reset size WebPositive Window Återställ storlek @@ -67,6 +70,7 @@ There was an error retrieving the bookmark folder.\n\nError: %error WebPositive Over 1 day left Download Window Över 1 dag kvar Downloads WebPositive Window Nerladdningar Requesting %url WebPositive Window Begär %url +Find next occurrence of search terms WebPositive Window find bar next button tooltip Sök nästa förekomst av söktermerna Apply Settings Window Tillämpa Bookmark info WebPositive Window Bokmärksinformation Size: Font Selection view Storlek: @@ -80,6 +84,7 @@ Open blank page Settings Window Öppna blank sida New tabs: Settings Window Ny flik Cancel WebPositive Window Avbryt Open all WebPositive Window Öppna alla +Proxy server requires authentication Settings Window Proxyservern kräver behörighetskontroll Clear URL Bar Töm Cut URL Bar Klipp ut Clear WebPositive Window Töm diff --git a/data/catalogs/kits/tracker/fi.catkeys b/data/catalogs/kits/tracker/fi.catkeys index a845ad861d..2987ff7db6 100644 --- a/data/catalogs/kits/tracker/fi.catkeys +++ b/data/catalogs/kits/tracker/fi.catkeys @@ -1,4 +1,4 @@ -1 finnish x-vnd.Haiku-libtracker 3375521561 +1 finnish x-vnd.Haiku-libtracker 4167158175 common B_COMMON_DIRECTORY yhteinen OK WidgetAttributeText Valmis Icon view VolumeWindow Kuvakenäkymä @@ -74,6 +74,7 @@ Arrange by ContainerWindow Järjestä: Mount server error AutoMounterSettings Liittämispalvelinvirhe Search FindPanel Haku Preparing to empty Trash… StatusWindow Valmistaudutaan tyhjentämään roskakori... +You cannot put the selected item(s) into the trash. FSUtils Et voi laittaa valittuja kohteita roskakoriin. Disks Model Levyt Create link ContainerWindow Luo linkki develop B_COMMON_DEVELOP_DIRECTORY kehitys diff --git a/data/catalogs/preferences/network/de.catkeys b/data/catalogs/preferences/network/de.catkeys index 4dc531d6e4..fe143ac3c3 100644 --- a/data/catalogs/preferences/network/de.catkeys +++ b/data/catalogs/preferences/network/de.catkeys @@ -1,22 +1,27 @@ -1 german x-vnd.Haiku-Network 365183238 +1 german x-vnd.Haiku-Network 1341378870 Choose automatically EthernetSettingsView Automatisch auswählen Gateway: EthernetSettingsView Gateway: Netmask: EthernetSettingsView Netzmaske: DHCP EthernetSettingsView DHCP DNS #2: EthernetSettingsView DNS #2: Apply EthernetSettingsView Anwenden +Netmask is invalid EthernetSettingsView Ungültige Netzmaske OK EthernetSettingsView OK DNS #1: EthernetSettingsView DNS #1: IP address: EthernetSettingsView IP-Adresse: Adapter: EthernetSettingsView Adapter: Domain: EthernetSettingsView Domäne: +Gateway is invalid EthernetSettingsView Ungültiges Gateway +DNS #1 is invalid EthernetSettingsView Ungültiger DNS #1 Revert EthernetSettingsView Anfangswerte EthernetSettingsView Network System name Netzwerk Mode: EthernetSettingsView Modus: +IP address is invalid EthernetSettingsView Ungültige IP-Adresse Network: EthernetSettingsView Netzwerk: The net_server needs to run for the auto configuration! EthernetSettingsView Zur Auto-Konfiguration muss der net_server laufen! Disabled EthernetSettingsView Deaktiviert Auto-configuring failed: EthernetSettingsView Auto-Konfiguration fehlgeschlagen: Static EthernetSettingsView Statisch +DNS #2 is invalid EthernetSettingsView Ungültiger DNS #2 EthernetSettingsView diff --git a/data/catalogs/preferences/network/hu.catkeys b/data/catalogs/preferences/network/hu.catkeys index d4ebca8532..0e8b4b07f8 100644 --- a/data/catalogs/preferences/network/hu.catkeys +++ b/data/catalogs/preferences/network/hu.catkeys @@ -1,22 +1,27 @@ -1 hungarian x-vnd.Haiku-Network 365183238 +1 hungarian x-vnd.Haiku-Network 1341378870 Choose automatically EthernetSettingsView Automatikus választás Gateway: EthernetSettingsView Átjáró: Netmask: EthernetSettingsView Hálózati maszk: DHCP EthernetSettingsView DHCP (automatikus) DNS #2: EthernetSettingsView DNS #2: Apply EthernetSettingsView Alkalmaz +Netmask is invalid EthernetSettingsView Az alhálózati maszk érvénytelen OK EthernetSettingsView Rendben DNS #1: EthernetSettingsView DNS #1: IP address: EthernetSettingsView IP-cím: Adapter: EthernetSettingsView Hálózati kártya: Domain: EthernetSettingsView Tartomány: +Gateway is invalid EthernetSettingsView Az átjáró érvénytelen +DNS #1 is invalid EthernetSettingsView Az elsődleges DNS érvénytelen Revert EthernetSettingsView Visszaállít EthernetSettingsView Network System name Hálózat Mode: EthernetSettingsView Beállítás: +IP address is invalid EthernetSettingsView Az IP-cím érvénytelen Network: EthernetSettingsView Hálózat: The net_server needs to run for the auto configuration! EthernetSettingsView A net_servernek futnia kell az automatikus beállításokhoz! Disabled EthernetSettingsView Letiltva Auto-configuring failed: EthernetSettingsView Az automatikus beállítás nem sikerült: Static EthernetSettingsView Állandó (kézi) +DNS #2 is invalid EthernetSettingsView A másodlagos DNS érvénytelen EthernetSettingsView diff --git a/data/catalogs/preferences/network/ja.catkeys b/data/catalogs/preferences/network/ja.catkeys index b3e99571d8..fbfceee648 100644 --- a/data/catalogs/preferences/network/ja.catkeys +++ b/data/catalogs/preferences/network/ja.catkeys @@ -1,22 +1,27 @@ -1 japanese x-vnd.Haiku-Network 365183238 +1 japanese x-vnd.Haiku-Network 1341378870 Choose automatically EthernetSettingsView 自動選択 Gateway: EthernetSettingsView ゲートウェイ: Netmask: EthernetSettingsView サブネットマスク: DHCP EthernetSettingsView 自動 (DHCP) DNS #2: EthernetSettingsView セカンダリ DNS サーバー: Apply EthernetSettingsView 適用 +Netmask is invalid EthernetSettingsView ネットマスクが正しくありません OK EthernetSettingsView Ok DNS #1: EthernetSettingsView プライマリ DNS サーバー: IP address: EthernetSettingsView IP アドレス: Adapter: EthernetSettingsView ネットワークアダプター: Domain: EthernetSettingsView ドメイン: +Gateway is invalid EthernetSettingsView ゲートウェイが正しくありません +DNS #1 is invalid EthernetSettingsView DNS #1 が正しくありません Revert EthernetSettingsView 元に戻す EthernetSettingsView <ワイヤレスネットワークが見つかりません> Network System name ネットワーク Mode: EthernetSettingsView モード: +IP address is invalid EthernetSettingsView IP アドレスが正しくありません Network: EthernetSettingsView ネットワーク: The net_server needs to run for the auto configuration! EthernetSettingsView 自動設定するには net_server が起動している必要があります! Disabled EthernetSettingsView 無効 Auto-configuring failed: EthernetSettingsView 自動設定に失敗しました: Static EthernetSettingsView 固定 IP +DNS #2 is invalid EthernetSettingsView DNS #2 が正しくありません EthernetSettingsView <アダプターがありません> diff --git a/data/catalogs/preferences/network/sv.catkeys b/data/catalogs/preferences/network/sv.catkeys index dd2db321a1..c7ac241b60 100644 --- a/data/catalogs/preferences/network/sv.catkeys +++ b/data/catalogs/preferences/network/sv.catkeys @@ -1,22 +1,27 @@ -1 swedish x-vnd.Haiku-Network 365183238 +1 swedish x-vnd.Haiku-Network 1341378870 Choose automatically EthernetSettingsView Välj automatiskt Gateway: EthernetSettingsView Gateway: Netmask: EthernetSettingsView Nätmask: DHCP EthernetSettingsView DHCP DNS #2: EthernetSettingsView Sekundär DNS: Apply EthernetSettingsView Använd +Netmask is invalid EthernetSettingsView Nätmasken är felaktig OK EthernetSettingsView Ok DNS #1: EthernetSettingsView Primär DNS: IP address: EthernetSettingsView IP-adress: Adapter: EthernetSettingsView Nätverkskort: Domain: EthernetSettingsView Domän: +Gateway is invalid EthernetSettingsView Gateway är ogiltig +DNS #1 is invalid EthernetSettingsView DNS #1 är ogiltig Revert EthernetSettingsView Återställ EthernetSettingsView Network System name Nätverk Mode: EthernetSettingsView Konfiguration: +IP address is invalid EthernetSettingsView IP-adressen är felaktig Network: EthernetSettingsView Nätverk: The net_server needs to run for the auto configuration! EthernetSettingsView Automatisk konfiguration kan inte ske utan att net_server körs! Disabled EthernetSettingsView Inaktiverad Auto-configuring failed: EthernetSettingsView Automatisk konfiguration misslyckades: Static EthernetSettingsView Statisk +DNS #2 is invalid EthernetSettingsView DNS #2 är ogiltig EthernetSettingsView diff --git a/data/catalogs/preferences/notifications/fi.catkeys b/data/catalogs/preferences/notifications/fi.catkeys index 8cd6347683..c231615623 100644 --- a/data/catalogs/preferences/notifications/fi.catkeys +++ b/data/catalogs/preferences/notifications/fi.catkeys @@ -1,4 +1,4 @@ -1 finnish x-vnd.Haiku-Notifications 814394708 +1 finnish x-vnd.Haiku-Notifications 2177286129 An error occurred saving the preferences.\nIt's possible you are running out of disk space. GeneralView Tapahtui virhe tallennettaessa asetuksia.\nOn mahdollista, että levytila on loppunut. Notifications GeneralView Ilmoitukset seconds of inactivity GeneralView joutilaisuussekunnit @@ -17,6 +17,7 @@ Cannot disable notifications because the server can't be reached. GeneralView I Progress NotificationView Edistyminen Last Received NotificationView Viimeksi vastaanotettu General PrefletView Yleistä +Apply PrefletWin Käytä Display PrefletView Näyttö Can't enable notifications at startup time, you probably don't have write permission to the boot settings directory. GeneralView Ilmoitusten ottaminen käyttöön käynnistysaikana epäonnistui. Sinulla ei luultavasti ole kirjoitusoikeutta alkulatausasetushakemistoon. Search: NotificationView Etsintä: diff --git a/data/catalogs/preferences/shortcuts/fi.catkeys b/data/catalogs/preferences/shortcuts/fi.catkeys index 76741a339d..4abbd2e251 100644 --- a/data/catalogs/preferences/shortcuts/fi.catkeys +++ b/data/catalogs/preferences/shortcuts/fi.catkeys @@ -1,4 +1,4 @@ -1 finnish x-vnd.Haiku-Shortcuts 3397621807 +1 finnish x-vnd.Haiku-Shortcuts 341885426 Error, NULL state description?\n ShortcutsSpec Virhe, NULL-tilakuvaus?\n MoveMouse ShortcutsSpec SiirräHiirtä OK ShortcutsWindow Valmis @@ -20,6 +20,7 @@ Shortcuts was couldn't open your KeySet file! ShortcutsWindow Pikanäppäinaset *Multi \"*MoveMouseTo 100% 0\" \"*MouseButton 1\" ShortcutsWindow *Moni ”*SiirräHiiriKohteeseen 100% 0” ”*Hiiripainike 1” SendMessage ShortcutsSpec LähetäViesti MoveMouseTo ShortcutsSpec SiirräHiiriKohteeseen +Option ShortcutsSpec Name for modifier on keyboard Valitsin Save ShortcutsWindow Tallenna *MouseButton 1 ShortcutsWindow *Hiiripainike 1 *MoveMouse +20 +0 ShortcutsWindow *SiirräHiiri +20 +0 diff --git a/data/catalogs/preferences/time/fi.catkeys b/data/catalogs/preferences/time/fi.catkeys index ddfd8ab012..96e2973d03 100644 --- a/data/catalogs/preferences/time/fi.catkeys +++ b/data/catalogs/preferences/time/fi.catkeys @@ -1,4 +1,4 @@ -1 finnish x-vnd.Haiku-Time 3544635877 +1 finnish x-vnd.Haiku-Time 3259467657 GMT (UNIX compatible) Time Greenwichin aika (UNIX-yhteensopiva) OK Time Valmis Asia Time Aasia @@ -11,6 +11,7 @@ Preview time: Time Esikatseluaika: Synchronize Time Synkronoi Revert Time Palauta Pacific Time Tyyni valtameri +Show day of week Time Näytä viikonpäivä Add Time Lisää Date and time Time Päivämäärä ja aika about Time Ohjelmasta @@ -26,6 +27,7 @@ Time Time Aika Indian Time Intia Sending request failed Time Pyynnön lähettäminen epäonnistui Arctic Time Pohjoinen napaseutu +Display time with seconds Time Näytä aika sekunteina Time System name Aika-asetukset America Time Amerikka Reset Time Nollaa @@ -33,6 +35,8 @@ Synchronize at boot Time Synkronoi alkulatauksen yhteydessä Time & Date, written by:\n\n\tAndrew Edward McCall\n\tMike Berg\n\tJulun\n\tPhilippe Saint-Pierre\n\nCopyright 2004-2012, Haiku. Time Time & Date, tekijät:\n\n\tAndrew Edward McCall\n\tMike Berg\n\tJulun\n\tPhilippe Saint-Pierre\n\nCopyright 2004-2012, Haiku. Received invalid time Time Vastaanotettiin virheellinen aika Antarctica Time Etelänapamanner +Show time zone Time Näytä aikavyöhyke +Show clock in Deskbar Time Näytä kello työpöytäpalkissa The following error occured while synchronizing:r\n%s: %s Time Seuraava virhe tapahtui synkronoinnin aikana:r\n%s: %s Time Current time: Time Nykyinen aika: diff --git a/docs/user/storage/NodeMonitor.dox b/docs/user/storage/NodeMonitor.dox index 7cc288c43b..3df7e78ea5 100644 --- a/docs/user/storage/NodeMonitor.dox +++ b/docs/user/storage/NodeMonitor.dox @@ -35,6 +35,9 @@ \var B_STOP_WATCHING Flag for watch_node(). Unsubscribe from watching a node. + + \attention \c B_STOP_WATCHING does not apply to volume watching, you must + call stop_watching() instead. */ @@ -329,13 +332,13 @@ - \c B_WATCH_ALL - \c B_WATCH_MOUNT - Note, that the latter two cases are not mutual exclusive, i.e. mount and + Note that the latter two cases are not mutual exclusive, i.e. mount and node watching can be requested with a single call. \param node node_ref referring to the node to be watched. May be \c NULL, if only mount watching is requested. \param flags Flags indicating the actions to be performed. - \param target Messenger referring to the target. Must be valid. + \param target BMessenger object referring to the \a target. \return \c B_OK if everything went fine, an error code otherwise. */ @@ -368,7 +371,7 @@ - \c B_WATCH_ALL - \c B_WATCH_MOUNT - Note, that the latter two cases are not mutual exlusive, i.e. mount and + Note that the latter two cases are not mutual exclusive, i.e. mount and node watching can be requested with a single call. \param node node_ref referring to the node to be watched. May be \c NULL, @@ -387,20 +390,41 @@ \fn status_t stop_watching(BMessenger target) \brief Unsubscribes \a target from node and mount monitoring. - \param target Messenger referring to the target. Must be valid. + You may still receive notification messages after calling stop_watching() + because while node monitoring is asynchronous and all changes are atomic, + message sending is not atomic so there is a lag time from when you + stop monitoring and when the message is received in your message receiving + thread. You can check the timestamp of the message to determine if + it was sent after stop_watching() was called. - \return \c B_OK if everything went fine, an error code otherwise. + \param target BMessenger object referring to the \a target. + + \return A status code. + \retval B_OK Stopped sending notification messages to the \a target. + \retval B_BAD_VALUE \a target was invalid. + \retval B_ENTRY_NOT_FOUND Node not found. */ /*! \fn status_t stop_watching(const BHandler *handler, const BLooper *looper) - \brief Unsubscribes \a target from node and mount monitoring. + \brief Unsubscribes \a handler or \a looper target from node and mount + monitoring. - \param handler The target handler. May be \c NULL, if \a looper is not - \c NULL. Then the preferred handler of the looper is targeted. - \param looper The target looper. May be \c NULL, if \a handler is not - \c NULL. Then the handler's looper is the target looper. + You may still receive notification messages after calling stop_watching() + because while node monitoring is asynchronous and all changes are atomic, + message sending is not atomic so there is a lag time from when you + stop monitoring and when the message is received in your message receiving + thread. You can check the timestamp of the message to determine if + it was sent after stop_watching() was called. - \return \c B_OK if everything went fine, an error code otherwise. + \param handler The target handler, may be \c NULL. If \a looper is not + \c NULL then the looper's preferred handler is targeted. + \param looper The target looper, may be \c NULL. If \a handler is not + \c NULL then the handler's looper is targeted. + + \return A status code. + \retval B_OK Stopped sending notification messages to the target. + \retval B_BAD_VALUE Target from \a handler or \a looper was invalid. + \retval B_ENTRY_NOT_FOUND Node not found. */ diff --git a/docs/user/storage/VolumeRoster.dox b/docs/user/storage/VolumeRoster.dox new file mode 100644 index 0000000000..e29bfba5c4 --- /dev/null +++ b/docs/user/storage/VolumeRoster.dox @@ -0,0 +1,131 @@ +/* + * Copyright 2002-2013 Haiku Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Vincent Dominguez + * John Scipione, jscipione@gmail.com + * Ingo Weinhold, bonefish@users.sf.net + * + * Corresponds to: + * headers/os/storage/VolumeRoster.h hrev45306 + * src/kits/storage/VolumeRoster.cpp hrev45306 + */ + + +/*! + \file VolumeRoster.h + \ingroup storage + \ingroup libbe + \brief Provides the BVolumeRoster class. +*/ + + +/*! + \class BVolumeRoster + \ingroup storage + \ingroup libbe + \brief Provides an interface for iterating through available volumes + and watching for mounting/unmounting. + + This class wraps the next_dev() function for iterating through the + list of available volumes and watch_node()/stop_watching() for + watching volumes. +*/ + + +/*! + \fn BVolumeRoster::BVolumeRoster() + \brief Creates a BVolumeRoster object. The object is ready to be used. +*/ + + +/*! + \fn BVolumeRoster::~BVolumeRoster() + \brief Deletes the volume roster and frees all associated resources. + + If a watch was activated (by StartWatching()), it is deactivated. +*/ + + + +/*! + \fn status_t BVolumeRoster::GetNextVolume(BVolume *volume) + \brief Fills out the passed in BVolume object with the next available + volume. + + \param volume A pointer to a pre-allocated BVolume object to be + initialized to the next available volume. + + \return A status code. + \retval B_OK Everything went fine. + \retval B_BAD_VALUE The last volume in the list was already returned. +*/ + + +/*! + \fn void BVolumeRoster::Rewind() + \brief Rewinds the list of available volumes back to the first item. + + The next call to GetNextVolume() will return the first available volume. +*/ + + +/*! + \fn status_t BVolumeRoster::GetBootVolume(BVolume *volume) + \brief Fills out the passed in BVolume object with the boot volume. + + Currently, this method looks for the volume that is mounted at "/boot". + The only way to fool the system into thinking that there is not a boot + volume is to rename "/boot" -- but, please refrain from doing this. + + \param volume A pointer to a pre-allocated BVolume to be initialized to + refer to the boot volume. + + \return A status code, \c B_OK if everything went fine or an error code + otherwise. +*/ + + +/*! + \fn status_t BVolumeRoster::StartWatching(BMessenger messenger) + \brief Starts watching the available volumes for changes. + + Notifications are sent to the specified target whenever a volume is + mounted or unmounted. The format of the notification messages is + described under watch_node(). Actually BVolumeRoster just provides a + more convenient interface for it. + + If StartWatching() has been called before with another target and no + StopWatching() since, StopWatching() is called first, so that the former + target won't receive any notifications anymore. + + When the object is destroyed all watching ends as well. + + \param messenger The target which the notification messages are sent. + + \return A status code. + \retval B_OK Everything went fine. + \retval B_BAD_VALUE The supplied BMessenger was invalid. + \retval B_NO_MEMORY There was insufficient memory to carry out this + operation. + + \see watch_node() +*/ + + +/*! + \fn void BVolumeRoster::StopWatching() + \brief Stops watching volumes initiated by StartWatching(). + + \see stop_watching() +*/ + + +/*! + \fn BMessenger BVolumeRoster::Messenger() const + \brief Returns the messenger currently watching the volume list. + + \return A messenger to the target currently watching the volume list, or + an invalid messenger if not watching. +*/ diff --git a/headers/os/app/Key.h b/headers/os/app/Key.h new file mode 100644 index 0000000000..35f166ec14 --- /dev/null +++ b/headers/os/app/Key.h @@ -0,0 +1,115 @@ +/* + * Copyright 2011, Haiku, Inc. + * Distributed under the terms of the MIT License. + */ +#ifndef _KEY_H +#define _KEY_H + + +#include +#include +#include +#include + + +enum BKeyPurpose { + B_KEY_PURPOSE_ANY, + B_KEY_PURPOSE_GENERIC, + B_KEY_PURPOSE_KEYRING, + B_KEY_PURPOSE_WEB, + B_KEY_PURPOSE_NETWORK, + B_KEY_PURPOSE_VOLUME +}; + + +enum BKeyType { + B_KEY_TYPE_ANY, + B_KEY_TYPE_GENERIC, + B_KEY_TYPE_PASSWORD, + B_KEY_TYPE_CERTIFICATE +}; + + +class BKey { +public: + BKey(); + BKey(BKeyPurpose purpose, + const char* identifier, + const char* secondaryIdentifier = NULL, + const uint8* data = NULL, + size_t length = 0); + BKey(BKey& other); + virtual ~BKey(); + + virtual BKeyType Type() const { return B_KEY_TYPE_GENERIC; }; + + void Unset(); + + status_t SetTo(BKeyPurpose purpose, + const char* identifier, + const char* secondaryIdentifier = NULL, + const uint8* data = NULL, + size_t length = 0); + + void SetPurpose(BKeyPurpose purpose); + BKeyPurpose Purpose() const; + + void SetIdentifier(const char* identifier); + const char* Identifier() const; + + void SetSecondaryIdentifier(const char* identifier); + const char* SecondaryIdentifier() const; + + status_t SetData(const uint8* data, size_t length); + size_t DataLength() const; + const uint8* Data() const; + status_t GetData(uint8* buffer, size_t bufferSize) const; + + const char* Owner() const; + bigtime_t CreationTime() const; + + virtual status_t Flatten(BMessage& message) const; + virtual status_t Unflatten(const BMessage& message); + + BKey& operator=(const BKey& other); + + bool operator==(const BKey& other) const; + bool operator!=(const BKey& other) const; + + virtual void PrintToStream(); + +private: + friend class BKeyStore; + + BKeyPurpose fPurpose; + BString fIdentifier; + BString fSecondaryIdentifier; + BString fOwner; + bigtime_t fCreationTime; + mutable BMallocIO fData; +}; + + +class BPasswordKey : public BKey { +public: + BPasswordKey(); + BPasswordKey(const char* password, + BKeyPurpose purpose, const char* identifier, + const char* secondaryIdentifier = NULL); + BPasswordKey(BPasswordKey& other); + virtual ~BPasswordKey(); + + virtual BKeyType Type() const { return B_KEY_TYPE_PASSWORD; }; + + status_t SetTo(const char* password, + BKeyPurpose purpose, + const char* identifier, + const char* secondaryIdentifier = NULL); + + status_t SetPassword(const char* password); + const char* Password() const; + + virtual void PrintToStream(); +}; + +#endif // _KEY_H diff --git a/headers/os/app/KeyStore.h b/headers/os/app/KeyStore.h new file mode 100644 index 0000000000..7c5a86d638 --- /dev/null +++ b/headers/os/app/KeyStore.h @@ -0,0 +1,103 @@ +/* + * Copyright 2011, Haiku, Inc. + * Distributed under the terms of the MIT License. + */ +#ifndef _KEY_STORE_H +#define _KEY_STORE_H + + +#include + + +class BKeyStore { +public: + BKeyStore(); + virtual ~BKeyStore(); + + status_t GetKey(BKeyType type, const char* identifier, + BKey& key); + status_t GetKey(BKeyType type, const char* identifier, + const char* secondaryIdentifier, BKey& key); + status_t GetKey(BKeyType type, const char* identifier, + const char* secondaryIdentifier, + bool secondaryIdentifierOptional, + BKey& key); + + status_t GetKey(const char* keyring, + BKeyType type, const char* identifier, + BKey& key); + status_t GetKey(const char* keyring, + BKeyType type, const char* identifier, + const char* secondaryIdentifier, BKey& key); + status_t GetKey(const char* keyring, + BKeyType type, const char* identifier, + const char* secondaryIdentifier, + bool secondaryIdentifierOptional, + BKey& key); + + status_t AddKey(const BKey& key); + status_t AddKey(const char* keyring, const BKey& key); + status_t RemoveKey(const BKey& key); + status_t RemoveKey(const char* keyring, const BKey& key); + + status_t GetNextKey(uint32& cookie, BKey& key); + status_t GetNextKey(BKeyType type, BKeyPurpose purpose, + uint32& cookie, BKey& key); + status_t GetNextKey(const char* keyring, + uint32& cookie, BKey& key); + status_t GetNextKey(const char* keyring, + BKeyType type, BKeyPurpose purpose, + uint32& cookie, BKey& key); + + // Keyrings + + status_t AddKeyring(const char* keyring); + status_t RemoveKeyring(const char* keyring); + + status_t GetNextKeyring(uint32& cookie, + BString& keyring); + + status_t SetUnlockKey(const char* keyring, + const BKey& key); + status_t RemoveUnlockKey(const char* keyring); + + // Master keyring + + status_t SetMasterUnlockKey(const BKey& key); + status_t RemoveMasterUnlockKey(); + + status_t AddKeyringToMaster(const char* keyring); + status_t RemoveKeyringFromMaster(const char* keyring); + + status_t GetNextMasterKeyring(uint32& cookie, + BString& keyring); + + // Locking + + bool IsKeyringUnlocked(const char* keyring); + status_t LockKeyring(const char* keyring); + status_t LockMasterKeyring(); + + // Applications + + status_t GetNextApplication(uint32& cookie, + BString& signature) const; + status_t GetNextApplication(const char* keyring, + uint32& cookie, BString& signature) const; + status_t RemoveApplication(const char* signature); + status_t RemoveApplication(const char* keyring, + const char* signature); + + // Service functions + + status_t GeneratePassword(BPasswordKey& password, + size_t length, uint32 flags); + float PasswordStrength(const char* password); + +private: + status_t _SendKeyMessage(BMessage& message, + BMessage* reply) const; +}; + + +#endif // _KEY_STORE_H diff --git a/headers/os/interface/Menu.h b/headers/os/interface/Menu.h index e5ab621649..60ba113883 100644 --- a/headers/os/interface/Menu.h +++ b/headers/os/interface/Menu.h @@ -122,6 +122,7 @@ public: float MaxContentWidth() const; BMenuItem* FindMarked(); + int32 FindMarkedIndex(); BMenu* Supermenu() const; BMenuItem* Superitem() const; diff --git a/headers/os/storage/VolumeRoster.h b/headers/os/storage/VolumeRoster.h index 235c06bc78..2f245144f8 100644 --- a/headers/os/storage/VolumeRoster.h +++ b/headers/os/storage/VolumeRoster.h @@ -36,8 +36,16 @@ private: private: int32 fCookie; + // The iteration cookie for next_dev() + // Initialized to 0 BMessenger* fTarget; + // BMessenger referring to the target to + // which the watching notification + // messages are sent. The object is + // allocated and owned by the roster, + // or NULL if not watching. uint32 _reserved[3]; + // FBC }; diff --git a/headers/private/app/KeyStoreDefs.h b/headers/private/app/KeyStoreDefs.h new file mode 100644 index 0000000000..0c1218c031 --- /dev/null +++ b/headers/private/app/KeyStoreDefs.h @@ -0,0 +1,48 @@ +/* + * Copyright 2012, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Michael Lotz, mmlr@mlotz.ch + */ +#ifndef _KEY_STORE_DEFS_H +#define _KEY_STORE_DEFS_H + + +namespace BPrivate { + + +const char* kKeyStoreServerSignature + = "application/x-vnd.Haiku-keystore_server"; + + +enum { + // Replies + KEY_STORE_SUCCESS = 'KRok', + KEY_STORE_ERROR = 'KRer', + KEY_STORE_RESULT = 'KRrs', + + // KeyStore requests + KEY_STORE_GET_KEY = 'KgtK', + KEY_STORE_GET_NEXT_KEY = 'KgnK', + KEY_STORE_ADD_KEY = 'KadK', + KEY_STORE_REMOVE_KEY = 'KrmK', + KEY_STORE_ADD_KEYRING = 'KaKR', + KEY_STORE_REMOVE_KEYRING = 'KrKR', + KEY_STORE_GET_NEXT_KEYRING = 'KnKR', + KEY_STORE_SET_UNLOCK_KEY = 'KsuK', + KEY_STORE_REMOVE_UNLOCK_KEY = 'KruK', + KEY_STORE_ADD_KEYRING_TO_MASTER = 'KarM', + KEY_STORE_REMOVE_KEYRING_FROM_MASTER = 'KrrM', + KEY_STORE_GET_NEXT_MASTER_KEYRING = 'KnrM', + KEY_STORE_IS_KEYRING_UNLOCKED = 'KuKR', + KEY_STORE_LOCK_KEYRING = 'KlKR', + KEY_STORE_GET_NEXT_APPLICATION = 'KnKA', + KEY_STORE_REMOVE_APPLICATION = 'KrKA', +}; + + +} // namespace BPrivate + + +#endif // _KEY_STORE_DEFS_H diff --git a/headers/private/interface/ColumnListView.h b/headers/private/interface/ColumnListView.h index 2acbbdbb6c..027154b98b 100644 --- a/headers/private/interface/ColumnListView.h +++ b/headers/private/interface/ColumnListView.h @@ -133,6 +133,7 @@ public: float Height() const; bool IsExpanded() const; + bool IsSelected() const; private: // Blows up into the debugger if the validation fails. @@ -326,8 +327,9 @@ public: // Does not delete row or children at this time. // todo: Make delete row and children void RemoveRow(BRow* row); - void UpdateRow(BRow* row); + bool SwapRows(int32 index1, int32 index2, BRow* + parentRow1 = NULL, BRow* parentRow2 = NULL); void Clear(); // Appearance (DEPRECATED) diff --git a/src/add-ons/accelerants/radeon_hd/display.cpp b/src/add-ons/accelerants/radeon_hd/display.cpp index 3400f083f4..321275c8ac 100644 --- a/src/add-ons/accelerants/radeon_hd/display.cpp +++ b/src/add-ons/accelerants/radeon_hd/display.cpp @@ -241,29 +241,6 @@ detect_crt_ranges(uint32 crtid) } -static void -remove_dup_displays(uint32 displayIndex, uint32 id) -{ - /* hack for both digital and analog interfaces active */ - if ((displayIndex > 0) && gDisplay[displayIndex]->attached) { - if (gConnector[id-1]->encoder.type == VIDEO_ENCODER_TMDS) { - int gpioID1 = gConnector[id-1]->gpioID; - int gpioID2 = gConnector[id]->gpioID; - edid1_info* edid = &gDisplay[displayIndex-1]->edidData; - - if ((gGPIOInfo[gpioID1]->hwPin == gGPIOInfo[gpioID2]->hwPin) && - edid->display.input_type) - // give preference to digital display when both are present - // and other display indicates it is digital - TRACE("%s: skipping connector %" B_PRIu32 - ": giving preference to digital " - "connector %d\n", __func__, id, id-1); - gDisplay[displayIndex]->attached = 0; - } - } -} - - status_t detect_displays() { @@ -332,45 +309,36 @@ detect_displays() gDisplay[displayIndex]->attached = connector_read_edid(id, &gDisplay[displayIndex]->edidData); - // Since DVI-I shows up as two connectors, and there is only one - // edid channel, we have to make *sure* the edid data received is - // valid for the connector. - // Found EDID data? if (gDisplay[displayIndex]->attached) { TRACE("%s: connector(%" B_PRIu32 "): found EDID data.\n", __func__, id); - bool analogEncoder - = gConnector[id]->encoder.type == VIDEO_ENCODER_TVDAC - || gConnector[id]->encoder.type == VIDEO_ENCODER_DAC; + if (gConnector[id]->type == VIDEO_CONNECTOR_DVII + || gConnector[id]->type == VIDEO_CONNECTOR_HDMIB) { + // These connectors can share gpio pins for data + // communication between digital and analog encoders + // (DVI-I is most common) + edid1_info* edid = &gDisplay[displayIndex]->edidData; - edid1_info* edid = &gDisplay[displayIndex]->edidData; - if (!edid->display.input_type && analogEncoder) { - // If non-digital EDID + the encoder is analog... - TRACE("%s: connector(%" B_PRIu32 "): has non-digital EDID " - "and a analog encoder.\n", __func__, id); - gDisplay[displayIndex]->attached - = encoder_analog_load_detect(id); - remove_dup_displays(displayIndex, id); - } else if (edid->display.input_type && !analogEncoder) { - // If EDID is digital, we make an assumption here. - TRACE("%s: connector(%" B_PRIu32 "): has digital EDID " - "and is not a analog encoder.\n", __func__, id); - } else { - // This generally means the monitor is of poor design - // Since we *know* there is no load on the analog encoder - // we assume that it is a digital display. - // This can also occur when a display has both DVI and VGA - // inputs and the graphics board has a DVI-I connector - // (reported as both digital and analog connectors) and the - // analog connection is the one in use. In that case, we - // get here when checking the digital connector and want - // to disable that display in favor of the analog one. - TRACE("%s: connector(%" B_PRIu32 "): Warning: monitor has " - "false digital EDID flag + unloaded analog encoder!\n", - __func__, id); - gDisplay[displayIndex]->attached = false; + bool analogEncoder + = gConnector[id]->encoder.type == VIDEO_ENCODER_TVDAC + || gConnector[id]->encoder.type == VIDEO_ENCODER_DAC; + bool digitalEncoder + = gConnector[id]->encoder.type == VIDEO_ENCODER_TMDS; + + bool digitalEdid = edid->display.input_type ? true : false; + + if (digitalEdid && analogEncoder) { + // Digital EDID + analog encoder? Lets try a load test + gDisplay[displayIndex]->attached + = encoder_analog_load_detect(id); + } else if (!digitalEdid && digitalEncoder) { + // non-digital EDID + digital encoder? Nope. + gDisplay[displayIndex]->attached = false; + } + + // Else... everything aligns as it should and attached = 1 } } } diff --git a/src/add-ons/accelerants/radeon_hd/encoder.cpp b/src/add-ons/accelerants/radeon_hd/encoder.cpp index 4064d2cb01..e8504df8bc 100644 --- a/src/add-ons/accelerants/radeon_hd/encoder.cpp +++ b/src/add-ons/accelerants/radeon_hd/encoder.cpp @@ -324,9 +324,6 @@ encoder_mode_set(uint8 crtcID) case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: - // already handled by virue of setting DPMS_OFF before - // getting here -#if 0 if ((info.chipsetFlags & CHIP_APU) != 0 || info.dceMajor >= 5) { // Setup DIG encoder @@ -359,7 +356,6 @@ encoder_mode_set(uint8 crtcID) transmitter_dig_setup(connectorIndex, pixelClock, 0, 0, ATOM_TRANSMITTER_ACTION_ENABLE); } -#endif break; case ENCODER_OBJECT_ID_INTERNAL_DDI: case ENCODER_OBJECT_ID_INTERNAL_DVO1: diff --git a/src/add-ons/decorators/BeDecorator/Jamfile b/src/add-ons/decorators/BeDecorator/Jamfile index 99e6d5fae8..b4acfb0991 100644 --- a/src/add-ons/decorators/BeDecorator/Jamfile +++ b/src/add-ons/decorators/BeDecorator/Jamfile @@ -6,9 +6,14 @@ UseHeaders [ FDirName $(HAIKU_TOP) src servers app drawing ] ; UseHeaders [ FDirName $(HAIKU_TOP) src servers app drawing Painter ] ; UsePrivateHeaders app shared interface graphics ; UseLibraryHeaders agg ; +UsePrivateHeaders kernel ; AddResources ClassicBe : resources.rdef ; +#TODO: See #8716, hrev44313 for ft2build.h: No such file or directory +#Includes [ FGristFiles BeDecorator.cpp ] +# : $(HAIKU_FREETYPE_HEADERS_DEPENDENCY) ; + Addon ClassicBe : BeDecorator.cpp : be app_server $(TARGET_LIBSTDC++) $(TARGET_LIBSUPC++) diff --git a/src/add-ons/decorators/MacDecorator/Jamfile b/src/add-ons/decorators/MacDecorator/Jamfile index 6ee87f0b4e..88ffb91998 100644 --- a/src/add-ons/decorators/MacDecorator/Jamfile +++ b/src/add-ons/decorators/MacDecorator/Jamfile @@ -8,9 +8,13 @@ UseHeaders [ FDirName $(HAIKU_TOP) src servers app drawing Painter ] ; UseHeaders [ FDirName $(HAIKU_TOP) src servers app font ] ; UsePrivateHeaders app shared interface graphics ; UseLibraryHeaders agg ; +UsePrivateHeaders kernel ; AddResources MacDecorator : resources.rdef ; +Includes [ FGristFiles MacDecorator.cpp ] + : $(HAIKU_FREETYPE_HEADERS_DEPENDENCY) ; + Addon MacDecorator : MacDecorator.cpp : be app_server $(TARGET_LIBSTDC++) diff --git a/src/add-ons/decorators/WinDecorator/Jamfile b/src/add-ons/decorators/WinDecorator/Jamfile index a0c60a2803..b472e5989b 100644 --- a/src/add-ons/decorators/WinDecorator/Jamfile +++ b/src/add-ons/decorators/WinDecorator/Jamfile @@ -6,9 +6,14 @@ UseHeaders [ FDirName $(HAIKU_TOP) src servers app drawing ] ; UseHeaders [ FDirName $(HAIKU_TOP) src servers app drawing Painter ] ; UsePrivateHeaders app shared interface graphics ; UseLibraryHeaders agg ; +UsePrivateHeaders kernel ; AddResources WinDecorator : resources.rdef ; +#TODO: See #8716, hrev44313 for ft2build.h: No such file or directory +#Includes [ FGristFiles WinDecorator.cpp ] +# : $(HAIKU_FREETYPE_HEADERS_DEPENDENCY) ; + Addon WinDecorator : WinDecorator.cpp : be app_server $(TARGET_LIBSTDC++) diff --git a/src/add-ons/kernel/drivers/network/wlan/iprowifi4965/dev/iwn/if_iwn.c b/src/add-ons/kernel/drivers/network/wlan/iprowifi4965/dev/iwn/if_iwn.c index 4ae4191617..53efcb5077 100644 --- a/src/add-ons/kernel/drivers/network/wlan/iprowifi4965/dev/iwn/if_iwn.c +++ b/src/add-ons/kernel/drivers/network/wlan/iprowifi4965/dev/iwn/if_iwn.c @@ -89,6 +89,7 @@ static const struct iwn_ident iwn_ident_table[] = { { 0x8086, 0x008b, "Intel Centrino Wireless-N 1030" }, { 0x8086, 0x0090, "Intel Centrino Advanced-N 6230" }, { 0x8086, 0x0091, "Intel Centrino Advanced-N 6230" }, + { 0x8086, 0x088e, "Intel Centrino Advanced-N 6235" }, { 0x8086, 0x0885, "Intel Centrino Wireless-N + WiMAX 6150" }, { 0x8086, 0x0886, "Intel Centrino Wireless-N + WiMAX 6150" }, { 0x8086, 0x0896, "Intel Centrino Wireless-N 130" }, diff --git a/src/apps/Jamfile b/src/apps/Jamfile index 7cd5efc724..6c3a8fc0ea 100644 --- a/src/apps/Jamfile +++ b/src/apps/Jamfile @@ -48,7 +48,7 @@ HaikuSubInclude powerstatus ; HaikuSubInclude processcontroller ; HaikuSubInclude pulse ; HaikuSubInclude remotedesktop ; -HaikuSubInclude resedit ; +HaikuSubInclude resourceedit ; HaikuSubInclude screenshot ; HaikuSubInclude serialconnect ; HaikuSubInclude showimage ; diff --git a/src/apps/activitymonitor/ActivityWindow.cpp b/src/apps/activitymonitor/ActivityWindow.cpp index 188289163e..f635ec63ae 100644 --- a/src/apps/activitymonitor/ActivityWindow.cpp +++ b/src/apps/activitymonitor/ActivityWindow.cpp @@ -29,7 +29,9 @@ #undef B_TRANSLATION_CONTEXT #define B_TRANSLATION_CONTEXT "ActivityWindow" + static const uint32 kMsgAddView = 'advw'; +static const uint32 kMsgAlwaysOnTop = 'alot'; static const uint32 kMsgShowSettings = 'shst'; @@ -131,6 +133,12 @@ ActivityWindow::ActivityWindow() menu = new BMenu(B_TRANSLATE("Settings")); menu->AddItem(new BMenuItem(B_TRANSLATE("Settings" B_UTF8_ELLIPSIS), new BMessage(kMsgShowSettings))); + + menu->AddSeparatorItem(); + fAlwaysOnTop = new BMenuItem(B_TRANSLATE("Always on top"), new BMessage(kMsgAlwaysOnTop)); + _SetAlwaysOnTop(settings.GetBool("always on top", false)); + menu->AddItem(fAlwaysOnTop); + menu->SetTargetForItems(this); menuBar->AddItem(menu); } @@ -201,6 +209,12 @@ ActivityWindow::MessageReceived(BMessage* message) break; } + case kMsgAlwaysOnTop: + { + _SetAlwaysOnTop(!fAlwaysOnTop->IsMarked()); + break; + } + case kMsgTimeIntervalUpdated: BroadcastToActivityViews(message); break; @@ -300,6 +314,10 @@ ActivityWindow::_SaveSettings() if (status != B_OK) return status; + status = settings.SetBool("always on top", fAlwaysOnTop->IsMarked()); + if (status != B_OK) + return status; + #ifdef __HAIKU__ BView* top = fLayout->View(); #else @@ -368,3 +386,11 @@ ActivityWindow::_MessageDropped(BMessage* message) } } + +void +ActivityWindow::_SetAlwaysOnTop(bool alwaysOnTop) +{ + SetFeel(alwaysOnTop ? B_FLOATING_ALL_WINDOW_FEEL : B_NORMAL_WINDOW_FEEL); + fAlwaysOnTop->SetMarked(alwaysOnTop); +} + diff --git a/src/apps/activitymonitor/ActivityWindow.h b/src/apps/activitymonitor/ActivityWindow.h index aa218aff50..0232cd80b5 100644 --- a/src/apps/activitymonitor/ActivityWindow.h +++ b/src/apps/activitymonitor/ActivityWindow.h @@ -37,11 +37,14 @@ private: void _AddDefaultView(); void _MessageDropped(BMessage *message); + void _SetAlwaysOnTop(bool alwaysOnTop); + BMenuItem* fAlwaysOnTop; #ifdef __HAIKU__ - BGroupLayout* fLayout; + BGroupLayout* fLayout; #endif - BMessenger fSettingsWindow; + BMessenger fSettingsWindow; + }; static const uint32 kMsgRemoveView = 'rmvw'; diff --git a/src/apps/deskbar/ExpandoMenuBar.cpp b/src/apps/deskbar/ExpandoMenuBar.cpp index 310d5ab9d4..6c23498f6e 100644 --- a/src/apps/deskbar/ExpandoMenuBar.cpp +++ b/src/apps/deskbar/ExpandoMenuBar.cpp @@ -337,66 +337,66 @@ TExpandoMenuBar::MouseDown(BPoint where) BMenuItem* menuItem; TTeamMenuItem* item = TeamItemAtPoint(where, &menuItem); - // check for three finger salute, a.k.a. Vulcan Death Grip - if (message != NULL && item != NULL && !fBarView->Dragging()) { - int32 modifiers = 0; - message->FindInt32("modifiers", &modifiers); - - if ((modifiers & B_COMMAND_KEY) != 0 - && (modifiers & B_CONTROL_KEY) != 0 - && (modifiers & B_SHIFT_KEY) != 0) { - const BList* teams = item->Teams(); - int32 teamCount = teams->CountItems(); - - team_id teamID; - for (int32 team = 0; team < teamCount; team++) { - teamID = (addr_t)teams->ItemAt(team); - kill_team(teamID); - // remove the team immediately from display - RemoveTeam(teamID, false); - } - - return; - } - - // control click - show all/hide all shortcut - if ((modifiers & B_CONTROL_KEY) != 0) { - // show/hide item's teams - BMessage showMessage((modifiers & B_SHIFT_KEY) != 0 - ? kMinimizeTeam : kBringTeamToFront); - showMessage.AddInt32("itemIndex", IndexOf(item)); - Window()->PostMessage(&showMessage, this); - return; - } - - // Check the bounds of the expand Team icon - if (fShowTeamExpander && fVertical) { - BRect expanderRect = item->ExpanderBounds(); - if (expanderRect.Contains(where)) { - // Let the update thread wait... - BAutolock locker(sMonLocker); - - // Toggle the item - item->ToggleExpandState(true); - item->Draw(); - - // Absorb the message. - return; - } - } - - // double-click on an item brings the team to front - int32 clicks; - if (message->FindInt32("clicks", &clicks) == B_OK && clicks > 1 - && item == menuItem && item == fLastClickItem) { - // activate this team - be_roster->ActivateApp((addr_t)item->Teams()->ItemAt(0)); - return; - } - - fLastClickItem = item; + if (message == NULL || item == NULL || fBarView->Dragging()) { + BMenuBar::MouseDown(where); + return; } + int32 modifiers = 0; + message->FindInt32("modifiers", &modifiers); + + // check for three finger salute, a.k.a. Vulcan Death Grip + if ((modifiers & B_COMMAND_KEY) != 0 + && (modifiers & B_CONTROL_KEY) != 0 + && (modifiers & B_SHIFT_KEY) != 0) { + const BList* teams = item->Teams(); + int32 teamCount = teams->CountItems(); + team_id teamID; + for (int32 team = 0; team < teamCount; team++) { + teamID = (addr_t)teams->ItemAt(team); + kill_team(teamID); + RemoveTeam(teamID, false); + // remove the team from display immediately + } + return; + // absorb the message + } + + // control click - show all/hide all shortcut + if ((modifiers & B_CONTROL_KEY) != 0) { + // show/hide item's teams + BMessage showMessage((modifiers & B_SHIFT_KEY) != 0 + ? kMinimizeTeam : kBringTeamToFront); + showMessage.AddInt32("itemIndex", IndexOf(item)); + Window()->PostMessage(&showMessage, this); + return; + // absorb the message + } + + // Check the bounds of the expand Team icon + if (fVertical && fShowTeamExpander) { + if (item->ExpanderBounds().Contains(where)) { + BAutolock locker(sMonLocker); + // let the update thread wait... + item->ToggleExpandState(true); + // toggle the item + item->Draw(); + return; + // absorb the message + } + } + + // double-click on an item brings the team to front + int32 clicks; + if (message->FindInt32("clicks", &clicks) == B_OK && clicks > 1 + && item == menuItem && item == fLastClickItem) { + be_roster->ActivateApp((addr_t)item->Teams()->ItemAt(0)); + // activate this team + return; + // absorb the message + } + + fLastClickItem = item; BMenuBar::MouseDown(where); } @@ -412,22 +412,38 @@ TExpandoMenuBar::MouseMoved(BPoint where, uint32 code, const BMessage* message) case B_ENTERED_VIEW: case B_INSIDE_VIEW: { - TTeamMenuItem* item = TeamItemAtPoint(where); - if (item == fLastMousedOverItem) { - // already set the tooltip for this item, break out - break; - } - - if (item == NULL) { + BMenuItem* menuItem; + TTeamMenuItem* item = TeamItemAtPoint(where, &menuItem); + TWindowMenuItem* windowMenuItem + = dynamic_cast(menuItem); + if (item == NULL || menuItem == NULL) { // item is NULL, remove the tooltip and break out fLastMousedOverItem = NULL; SetToolTip((const char*)NULL); break; } + if (menuItem == fLastMousedOverItem) { + // already set the tooltip for this item, break out + break; + } + + if (windowMenuItem != NULL && fBarView->Vertical() + && fBarView->ExpandoState() && item->IsExpanded()) { + // expando mode window menu item + fLastMousedOverItem = menuItem; + if (strcmp(windowMenuItem->Label(), + windowMenuItem->FullTitle()) != 0) { + // label is truncated, set tooltip + SetToolTip(windowMenuItem->FullTitle()); + } else + SetToolTip((const char*)NULL); + break; + } + if (item->HasLabel()) { // item has a visible label, remove the tooltip and break out - fLastMousedOverItem = item; + fLastMousedOverItem = menuItem; SetToolTip((const char*)NULL); break; } @@ -435,8 +451,8 @@ TExpandoMenuBar::MouseMoved(BPoint where, uint32 code, const BMessage* message) // new item, set the tooltip to the item name SetToolTip(item->Name()); - // save the current item for the next MouseMoved() call - fLastMousedOverItem = item; + // save the current menuitem for the next MouseMoved() call + fLastMousedOverItem = menuItem; break; } diff --git a/src/apps/deskbar/ExpandoMenuBar.h b/src/apps/deskbar/ExpandoMenuBar.h index 79f628cda8..b50a085d08 100644 --- a/src/apps/deskbar/ExpandoMenuBar.h +++ b/src/apps/deskbar/ExpandoMenuBar.h @@ -107,7 +107,7 @@ class TExpandoMenuBar : public BMenuBar { TTeamMenuItem* fPreviousDragTargetItem; - TTeamMenuItem* fLastMousedOverItem; + BMenuItem* fLastMousedOverItem; BMenuItem* fLastClickItem; static bool sDoMonitor; diff --git a/src/apps/deskbar/StatusView.cpp b/src/apps/deskbar/StatusView.cpp index 947773f531..b25c7af420 100644 --- a/src/apps/deskbar/StatusView.cpp +++ b/src/apps/deskbar/StatusView.cpp @@ -433,7 +433,9 @@ TReplicantTray::ShowHideTime() if (fTime == NULL) return; - if (fTime->IsHidden()) + // Check from the point of view of fTime because we need to ignore + // whether or not the parent window is hidden. + if (fTime->IsHidden(fTime)) fTime->Show(); else fTime->Hide(); @@ -441,7 +443,8 @@ TReplicantTray::ShowHideTime() RealignReplicants(); AdjustPlacement(); - bool showClock = !fTime->IsHidden(); + // Check from the point of view of fTime ignoring parent's state. + bool showClock = !fTime->IsHidden(fTime); // Update showClock setting that gets saved to disk on quit ((TBarApp*)be_app)->Settings()->showClock = showClock; diff --git a/src/apps/deskbar/TimeView.cpp b/src/apps/deskbar/TimeView.cpp index 0c6d0c8c10..8559fe8103 100644 --- a/src/apps/deskbar/TimeView.cpp +++ b/src/apps/deskbar/TimeView.cpp @@ -69,6 +69,7 @@ TTimeView::TTimeView(float maxWidth, float height) fMaxWidth(maxWidth), fHeight(height), fOrientation(true), + fShowLevel(0), fShowSeconds(false), fShowDayOfWeek(false), fShowTimeZone(false) @@ -116,10 +117,11 @@ status_t TTimeView::Archive(BMessage* data, bool deep) const { BView::Archive(data, deep); + data->AddBool("orientation", fOrientation); + data->AddInt16("showLevel", fShowLevel); data->AddBool("showSeconds", fShowSeconds); data->AddBool("showDayOfWeek", fShowDayOfWeek); data->AddBool("showTimeZone", fShowTimeZone); - data->AddBool("orientation", fOrientation); data->AddInt32("deskbar:private_align", B_ALIGN_RIGHT); return B_OK; diff --git a/src/apps/deskbar/TimeView.h b/src/apps/deskbar/TimeView.h index 129b2021fb..ba823dda06 100644 --- a/src/apps/deskbar/TimeView.h +++ b/src/apps/deskbar/TimeView.h @@ -133,16 +133,14 @@ private: float fMaxWidth; float fHeight; - bool fOrientation; // vertical = true + bool fOrientation; + // vertical = true + int16 fShowLevel; - bool fOverrideLocale; - bool fUse24HourClock; bool fShowSeconds; bool fShowDayOfWeek; bool fShowTimeZone; - BString fTimeFormat; - BPoint fTimeLocation; BPoint fDateLocation; diff --git a/src/apps/resourceedit/Constants.h b/src/apps/resourceedit/Constants.h new file mode 100644 index 0000000000..1bb2e97590 --- /dev/null +++ b/src/apps/resourceedit/Constants.h @@ -0,0 +1,53 @@ +/* + * Copyright 2012-2013 Tri-Edge AI + * All rights reserved. Distributed under the terms of the MIT license. + */ +#ifndef CONSTANTS_H +#define CONSTANTS_H + + +#define MSG_NEW 'm000' +#define MSG_OPEN 'm001' +#define MSG_OPEN_DONE 'm002' +#define MSG_CLOSE 'm003' +#define MSG_SAVE 'm004' +#define MSG_SAVEAS 'm005' +#define MSG_SAVEAS_DONE 'm006' +#define MSG_SAVEALL 'm007' +#define MSG_MERGEWITH 'm008' +#define MSG_QUIT 'm009' + +#define MSG_UNDO 'm010' +#define MSG_REDO 'm011' +#define MSG_CUT 'm012' +#define MSG_COPY 'm013' +#define MSG_PASTE 'm014' +#define MSG_CLEAR 'm015' +#define MSG_SELECTALL 'm016' + +#define MSG_ADDAPPRES 'm020' +#define MSG_SETTINGS 'm021' + +#define MSG_ADD 'm030' +#define MSG_REMOVE 'm031' +#define MSG_MOVEUP 'm032' +#define MSG_MOVEDOWN 'm033' + +#define MSG_SELECTION 'm040' +#define MSG_INVOCATION 'm041' + +#define MSG_ACCEPT 'm050' +#define MSG_CANCEL 'm051' +#define MSG_IGNORE 'm052' + +#define MSG_SETTINGS_APPLY 'm022' +#define MSG_SETTINGS_REVERT 'm023' +#define MSG_SETTINGS_CLOSED 'm024' + +// TODO: Remove prior to release. +#define DEBUG 1 +#include +// --- --- + + +#endif diff --git a/src/apps/resourceedit/DefaultTypes.cpp b/src/apps/resourceedit/DefaultTypes.cpp new file mode 100644 index 0000000000..3fed852f9c --- /dev/null +++ b/src/apps/resourceedit/DefaultTypes.cpp @@ -0,0 +1,47 @@ +/* + * Copyright 2012-2013 Tri-Edge AI + * All rights reserved. Distributed under the terms of the MIT license. + */ + + +#include "DefaultTypes.h" + +#include + + +int32 +ResourceType::FindIndex(type_code code) +{ + for (int32 i = 0; kDefaultTypes[i].type != NULL; i++) + if (StringToCode(kDefaultTypes[i].code) == code) + return i; + + return -1; +} + + +int32 +ResourceType::FindIndex(const char* type) +{ + for (int32 i = 0; kDefaultTypes[i].type != NULL; i++) + if (strcmp(kDefaultTypes[i].type, type) == 0) + return i; + + return -1; +} + + +void +ResourceType::CodeToString(type_code code, char* str) +{ + *(type_code*)str = B_HOST_TO_BENDIAN_INT32(code); + str[4] = '\0'; +} + + +type_code +ResourceType::StringToCode(const char* code) +{ + // TODO: Code may be in other formats, too! Ex.: 0x4C4F4E47 + return B_BENDIAN_TO_HOST_INT32(*(int32*)code); +} diff --git a/src/apps/resourceedit/DefaultTypes.h b/src/apps/resourceedit/DefaultTypes.h new file mode 100644 index 0000000000..ef51b66aa1 --- /dev/null +++ b/src/apps/resourceedit/DefaultTypes.h @@ -0,0 +1,69 @@ +/* + * Copyright 2012-2013 Tri-Edge AI + * All rights reserved. Distributed under the terms of the MIT license. + */ +#ifndef DEFAULT_TYPES_H +#define DEFAULT_TYPES_H + + +#include "AppFlagsEdit.h" +#include "BooleanEdit.h" +#include "EditView.h" +#include "NormalEdit.h" +#include "ResourceRow.h" + +#include + + +struct ResourceType { + const char* type; + const char* code; + const char* data; + uint32 size; + EditView* edit; + + static int32 FindIndex(const char* type); + static int32 FindIndex(type_code code); + + static void CodeToString(type_code code, char* str); + static type_code StringToCode(const char* code); +}; + + +#define LINE "", "", "", ~0, NULL +#define END NULL, NULL, NULL, 0, NULL + +const ResourceType kDefaultTypes[] = { + { "app_signature", "", "application/MyApp", 18, new NormalEdit() }, + { "app_name_catalog_entry", "", "MyApp:System name:MyApp", 24, new NormalEdit() }, + //{ "app_flags", "", "None", 4, NULL }, + { LINE }, + { "bool", "BOOL", "false", 1, new BooleanEdit() }, + { LINE }, + { "int8", "BYTE", "0", 1, new NormalEdit() }, + { "int16", "SHRT", "0", 2, new NormalEdit() }, + { "int32", "LONG", "0", 4, new NormalEdit() }, + { "int64", "LLNG", "0", 8, new NormalEdit() }, + { LINE }, + { "uint8", "UBYT", "0", 1, new NormalEdit() }, + { "uint16", "USHT", "0", 2, new NormalEdit() }, + { "uint32", "ULNG", "0", 4, new NormalEdit() }, + { "uint64", "ULLG", "0", 8, new NormalEdit() }, + { LINE }, + { "string", "CSTR", "\"\"", 0, NULL }, + { "raw", "RAWT", "", 0, NULL }, + { LINE }, + { "array", "", "", 0, NULL }, + { "message", "", "", 0, NULL }, + { "import", "", "", 0, NULL }, + { END } +}; + +const int32 kDefaultTypeSelected = 8; + // int32 + +#undef LINE +#undef END + + +#endif diff --git a/src/apps/resourceedit/EditWindow.cpp b/src/apps/resourceedit/EditWindow.cpp new file mode 100644 index 0000000000..73b03644ae --- /dev/null +++ b/src/apps/resourceedit/EditWindow.cpp @@ -0,0 +1,163 @@ +/* + * Copyright 2012-2013 Tri-Edge AI + * All rights reserved. Distributed under the terms of the MIT license. + */ + + +#include "EditWindow.h" + +#include "Constants.h" +#include "DefaultTypes.h" +#include "EditView.h" +#include "ResourceRow.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +EditWindow::EditWindow(BRect frame, ResourceRow* row) + : + BWindow(frame, "Edit Resource", + B_TITLED_WINDOW_LOOK, B_MODAL_APP_WINDOW_FEEL, 0) +{ + int32 ix = ResourceType::FindIndex(row->ResourceType()); + + fRow = row; + + fView = new BView(Bounds(), "fView", B_FOLLOW_ALL, 0); + fView->SetLayout(new BGroupLayout(B_VERTICAL)); + + fIDText = new BTextControl(BRect(0, 0, 0, 0), + "fIDText", "ID:", row->ResourceStringID(), NULL); + fIDText->SetDivider(50); + + fNameText = new BTextControl(BRect(0, 0, 0, 0), + "fNameText", "Name:", row->ResourceName(), NULL); + fNameText->SetDivider(50); + + fTypePopUp = new BPopUpMenu("(Type)"); + + // TODO: (Not so) evil redundancy. + for (int32 i = 0; kDefaultTypes[i].type != NULL; i++) { + if (kDefaultTypes[i].size == ~(uint32)0) + fTypePopUp->AddSeparatorItem(); + else + fTypePopUp->AddItem(new BMenuItem(kDefaultTypes[i].type, + new BMessage(MSG_SELECTION))); + } + // --- + + fTypePopUp->ItemAt(ix)->SetMarked(true); + + fTypeMenu = new BMenuField(BRect(0, 0, 0, 0), + "fTypeMenu", "Type:", fTypePopUp); + fTypeMenu->SetDivider(50); + + fCodeText = new BTextControl(BRect(0, 0, 0, 0), + "fCodeText", "Code:", row->ResourceStringCode(), NULL); + fCodeText->SetDivider(50); + + fEditViewBox = new BBox(BRect(0, 0, 0, 0), "fEditViewBox"); + fEditViewBox->SetLayout(new BGroupLayout(B_VERTICAL)); + + fEditView = kDefaultTypes[ix].edit; + fEditView->AttachTo(fEditViewBox); + fEditView->Edit(fRow); + + fErrorString = new BStringView(BRect(0, 0, 0, 0), + "fErrorString", ""); + + fErrorString->SetHighColor(ui_color(B_FAILURE_COLOR)); + + fCancelButton = new BButton(BRect(0, 0, 0, 0), + "fCancelButton", "Cancel", new BMessage(MSG_CANCEL)); + fOKButton = new BButton(BRect(0, 0, 0, 0), + "fOKButton", "OK", new BMessage(MSG_ACCEPT)); + + fView->AddChild(BGroupLayoutBuilder(B_VERTICAL, 8) + .Add(fIDText) + .Add(fNameText) + .Add(fTypeMenu) + .Add(fCodeText) + .Add(fEditViewBox) + .Add(fErrorString) + .Add(BGroupLayoutBuilder(B_HORIZONTAL, 8) + .AddGlue() + .Add(fCancelButton) + .Add(fOKButton) + .SetInsets(8, 8, 8, 8) + ) + .SetInsets(8, 8, 8, 8) + ); + + AddChild(fView); + ResizeTo(250, 350); + + Show(); +} + + +EditWindow::~EditWindow() +{ + fEditView->RemoveSelf(); +} + + +void +EditWindow::MessageReceived(BMessage* msg) +{ + switch (msg->what) { + case MSG_SELECTION: + { + int32 ix = fTypePopUp->FindMarkedIndex(); + + fCodeText->SetText(kDefaultTypes[ix].code); + + fEditView->RemoveSelf(); + + fEditView = kDefaultTypes[ix].edit; + fEditView->AttachTo(fEditViewBox); + fEditView->Edit(fRow); + + break; + } + case MSG_CANCEL: + PostMessage(B_QUIT_REQUESTED); + break; + + case MSG_ACCEPT: + { + if (_Validate()) { + int32 ix = fTypePopUp->FindMarkedIndex(); + + fRow->SetResourceStringID(fIDText->Text()); + fRow->SetResourceName(fNameText->Text()); + fRow->SetResourceType(kDefaultTypes[ix].type); + fRow->SetResourceStringCode(fCodeText->Text()); + fRow->SetResourceSize(kDefaultTypes[ix].size); + + fEditView->Commit(); + + PostMessage(B_QUIT_REQUESTED); + } + + break; + } + } +} + + +bool +EditWindow::_Validate() +{ + // TODO: Implement validation of entered data. + fErrorString->SetText(""); + return true; +} diff --git a/src/apps/resourceedit/EditWindow.h b/src/apps/resourceedit/EditWindow.h new file mode 100644 index 0000000000..d104af98fb --- /dev/null +++ b/src/apps/resourceedit/EditWindow.h @@ -0,0 +1,53 @@ +/* + * Copyright 2012-2013 Tri-Edge AI + * All rights reserved. Distributed under the terms of the MIT license. + */ +#ifndef EDIT_WINDOW_H +#define EDIT_WINDOW_H + + +#include + + +class EditView; +class ResourceRow; + +class BBox; +class BButton; +class BMenuField; +class BPopUpMenu; +class BStringView; +class BTextControl; + + +class EditWindow : public BWindow { +public: + EditWindow(BRect frame, ResourceRow* row); + ~EditWindow(); + + void MessageReceived(BMessage* msg); + +private: + ResourceRow* fRow; + + BView* fView; + + BTextControl* fIDText; + BTextControl* fNameText; + BPopUpMenu* fTypePopUp; + BMenuField* fTypeMenu; + BTextControl* fCodeText; + + EditView* fEditView; + BBox* fEditViewBox; + + BStringView* fErrorString; + + BButton* fCancelButton; + BButton* fOKButton; + + bool _Validate(); +}; + + +#endif diff --git a/src/apps/resourceedit/Jamfile b/src/apps/resourceedit/Jamfile new file mode 100644 index 0000000000..b392f77ea4 --- /dev/null +++ b/src/apps/resourceedit/Jamfile @@ -0,0 +1,54 @@ +SubDir HAIKU_TOP src apps resourceedit ; + +UsePrivateHeaders interface shared ; + +local sourceDirs = + edits + interface + settings + support +; + +local sourceDir ; + +for sourceDir in $(sourceDirs) { + SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src apps resourceedit $(sourceDir) ] ; +} + +Application ResourceEdit + : + # edits + AppFlagsEdit.cpp + BooleanEdit.cpp + EditView.cpp + NormalEdit.cpp + + # interface + ImageButton.cpp + + # settings + GenericSettingsView.cpp + + # support + UndoContext.cpp + + # . + DefaultTypes.cpp + EditWindow.cpp + MainWindow.cpp + ResourceEdit.cpp + ResourceListView.cpp + ResourceRow.cpp + SettingsFile.cpp + SettingsWindow.cpp + + main.cpp + : + be + tracker + translation + libcolumnlistview.a + $(TARGET_LIBSTDC++) + : + ResourceEdit.rdef +; diff --git a/src/apps/resourceedit/MainWindow.cpp b/src/apps/resourceedit/MainWindow.cpp new file mode 100644 index 0000000000..ae04c01af8 --- /dev/null +++ b/src/apps/resourceedit/MainWindow.cpp @@ -0,0 +1,1212 @@ +/* + * Copyright 2012-2013 Tri-Edge AI + * All rights reserved. Distributed under the terms of the MIT license. + */ + + +#include "MainWindow.h" + +#include "Constants.h" +#include "EditWindow.h" +#include "ImageButton.h" +#include "ResourceListView.h" +#include "ResourceRow.h" +#include "SettingsFile.h" +#include "SettingsWindow.h" +#include "UndoContext.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +using namespace std; + + +MainWindow::MainWindow(BRect frame, BEntry* assocEntry, SettingsFile* settings) + : + BWindow(frame, NULL, B_DOCUMENT_WINDOW, B_OUTLINE_RESIZE) +{ + fAssocEntry = assocEntry; + fSettings = settings; + + fUndoContext = new UndoContext(); + + AdaptSettings(); + + fSavePanel = NULL; + fUnsavedChanges = false; + + fMenuBar = new BMenuBar(BRect(0, 0, 600, 1), "fMenuBar"); + + fFileMenu = new BMenu("File", B_ITEMS_IN_COLUMN); + fNewItem = new BMenuItem("New", new BMessage(MSG_NEW), 'N'); + fOpenItem = new BMenuItem("Open", new BMessage(MSG_OPEN), 'O'); + fCloseItem = new BMenuItem("Close", new BMessage(MSG_CLOSE), 'W'); + fSaveItem = new BMenuItem("Save", new BMessage(MSG_SAVE), 'S'); + fSaveAsItem = new BMenuItem("Save As" B_UTF8_ELLIPSIS, new + BMessage(MSG_SAVEAS)); + fSaveAllItem = new BMenuItem("Save All", new BMessage(MSG_SAVEALL), 'S', + B_SHIFT_KEY); + fMergeWithItem = new BMenuItem("Merge With" B_UTF8_ELLIPSIS, + new BMessage(MSG_MERGEWITH), 'M'); + fQuitItem = new BMenuItem("Quit", new BMessage(MSG_QUIT), 'Q'); + + fEditMenu = new BMenu("Edit", B_ITEMS_IN_COLUMN); + fUndoItem = new BMenuItem("Undo", new BMessage(MSG_UNDO), 'Z'); + fUndoItem->SetEnabled(false); + fRedoItem = new BMenuItem("Redo", new BMessage(MSG_REDO), 'Y'); + fRedoItem->SetEnabled(false); + fCutItem = new BMenuItem("Cut", new BMessage(MSG_CUT), 'X'); + fCutItem->SetEnabled(false); + fCopyItem = new BMenuItem("Copy", new BMessage(MSG_COPY), 'C'); + fCopyItem->SetEnabled(false); + fPasteItem = new BMenuItem("Paste", new BMessage(MSG_PASTE), 'V'); + fPasteItem->SetEnabled(false); + fClearItem = new BMenuItem("Clear", new BMessage(MSG_CLEAR)); + fSelectAllItem = new BMenuItem("Select All", + new BMessage(MSG_SELECTALL), 'A'); + + fToolsMenu = new BMenu("Tools", B_ITEMS_IN_COLUMN); + fAddAppResourcesItem = new BMenuItem("Add app resources", + new BMessage(MSG_ADDAPPRES)); + fSettingsItem = new BMenuItem("Settings", new BMessage(MSG_SETTINGS)); + + fHelpMenu = new BMenu("Help", B_ITEMS_IN_COLUMN); + + fResourceIDText = new BTextControl(BRect(0, 0, 47, 23).OffsetBySelf(8, 24), + "fResourceIDText", NULL, "0", NULL); + fResourceTypePopUp = new BPopUpMenu("(Type)"); + fResourceTypeMenu = new BMenuField(BRect(0, 0, 1, 1).OffsetBySelf(60, 24), + "fResourceTypeMenu", NULL, fResourceTypePopUp); + + for (int32 i = 0; kDefaultTypes[i].type != NULL; i++) { + if (kDefaultTypes[i].size == ~(uint32)0) + fResourceTypePopUp->AddSeparatorItem(); + else + fResourceTypePopUp->AddItem( + new BMenuItem(kDefaultTypes[i].type, NULL)); + } + + fResourceTypePopUp->ItemAt(kDefaultTypeSelected)->SetMarked(true); + + fToolbarView = new BView(BRect(0, 0, 600, 51), "fToolbarView", + B_FOLLOW_LEFT_RIGHT, 0); + + fToolbarView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + + BRect toolRect = BRect(0, 0, 23, 23).OffsetBySelf(8, 24); + + fAddButton = new ImageButton(toolRect.OffsetBySelf(200, 0), + "fAddButton", BTranslationUtils::GetBitmap('PNG ', "add.png"), + new BMessage(MSG_ADD), B_FOLLOW_NONE); + fAddButton->ResizeTo(23, 23); + + fRemoveButton = new ImageButton(toolRect.OffsetBySelf(30, 0), + "fRemoveButton", BTranslationUtils::GetBitmap('PNG ', "remove.png"), + new BMessage(MSG_REMOVE), B_FOLLOW_NONE); + fRemoveButton->ResizeTo(23, 23); + fRemoveButton->SetEnabled(false); + + fMoveUpButton = new ImageButton(toolRect.OffsetBySelf(30, 0), + "fMoveUpButton", BTranslationUtils::GetBitmap('PNG ', "moveup.png"), + new BMessage(MSG_MOVEUP), B_FOLLOW_NONE); + fMoveUpButton->ResizeTo(23, 23); + fMoveUpButton->SetEnabled(false); + + fMoveDownButton = new ImageButton(toolRect.OffsetBySelf(30, 0), + "fMoveDownButton", BTranslationUtils::GetBitmap('PNG ', "movedown.png"), + new BMessage(MSG_MOVEDOWN), B_FOLLOW_NONE); + fMoveDownButton->ResizeTo(23, 23); + fMoveDownButton->SetEnabled(false); + + BRect listRect = Bounds(); + listRect.SetLeftTop(BPoint(0, 52)); + listRect.InsetBy(-1, -1); + + fResourceList = new ResourceListView(listRect, "fResourceList", + B_FOLLOW_ALL, 0); + + fResourceList->AddColumn(new BStringColumn("ID", 48, 1, 999, + B_ALIGN_LEFT), 0); + fResourceList->AddColumn(new BStringColumn("Name", 156, 1, 999, + B_TRUNCATE_END, B_ALIGN_LEFT), 1); + fResourceList->AddColumn(new BStringColumn("Type", 56, 1, 999, + B_TRUNCATE_END, B_ALIGN_CENTER), 2); + fResourceList->AddColumn(new BStringColumn("Code", 56, 1, 999, + B_TRUNCATE_END, B_ALIGN_CENTER), 3); + fResourceList->AddColumn(new BStringColumn("Data", 156, 1, 999, + B_TRUNCATE_END, B_ALIGN_LEFT), 4); + fResourceList->AddColumn(new BSizeColumn("Size", 74, 1, 999, + B_ALIGN_RIGHT), 5); + + //fResourceList->SetLatchWidth(0); + + fResourceList->SetTarget(this); + fResourceList->SetSelectionMessage(new BMessage(MSG_SELECTION)); + fResourceList->SetInvocationMessage(new BMessage(MSG_INVOCATION)); + + fStatsString = new BStringView(BRect(3, 2, 150, 13), "fStatsString", ""); + fStatsString->SetFontSize(11.0f); + + fStatsBox = new BBox(BRect(0, 0, 150, 16), "fStatsBox"); + fStatsBox->SetBorder(B_PLAIN_BORDER); + + AddChild(fMenuBar); + + fMenuBar->AddItem(fFileMenu); + fFileMenu->AddItem(fNewItem); + fFileMenu->AddItem(fOpenItem); + fFileMenu->AddItem(fCloseItem); + fFileMenu->AddSeparatorItem(); + fFileMenu->AddItem(fSaveItem); + fFileMenu->AddItem(fSaveAsItem); + fFileMenu->AddItem(fSaveAllItem); + fFileMenu->AddItem(fMergeWithItem); + fFileMenu->AddSeparatorItem(); + fFileMenu->AddItem(fQuitItem); + + fMenuBar->AddItem(fEditMenu); + fEditMenu->AddItem(fUndoItem); + fEditMenu->AddItem(fRedoItem); + fEditMenu->AddSeparatorItem(); + fEditMenu->AddItem(fCutItem); + fEditMenu->AddItem(fCopyItem); + fEditMenu->AddItem(fPasteItem); + fEditMenu->AddItem(fClearItem); + fEditMenu->AddSeparatorItem(); + fEditMenu->AddItem(fSelectAllItem); + + fMenuBar->AddItem(fToolsMenu); + fToolsMenu->AddItem(fAddAppResourcesItem); + fToolsMenu->AddSeparatorItem(); + fToolsMenu->AddItem(fSettingsItem); + + fMenuBar->AddItem(fHelpMenu); + + fToolbarView->AddChild(fResourceIDText); + fToolbarView->AddChild(fResourceTypeMenu); + + fToolbarView->AddChild(fAddButton); + fToolbarView->AddChild(fRemoveButton); + fToolbarView->AddChild(fMoveUpButton); + fToolbarView->AddChild(fMoveDownButton); + + AddChild(fToolbarView); + + AddChild(fResourceList); + fResourceList->AddStatusView(fStatsBox); + fStatsBox->AddChild(fStatsString); + + if (assocEntry != NULL) { + _SetTitleFromEntry(); + _Load(); + } else { + SetTitle("ResourceEdit | " B_UTF8_ELLIPSIS); + } +} + + +MainWindow::~MainWindow() +{ + delete fUndoContext; +} + + +bool +MainWindow::QuitRequested() +{ + // CAUTION: Do not read the body of this function if you + // are known to suffer from gotophobia. + + if (fUnsavedChanges) { + Activate(); + + char nameBuffer[B_FILE_NAME_LENGTH]; + + if (fAssocEntry != NULL) + fAssocEntry->GetName(nameBuffer); + else + strcpy(nameBuffer, "Untitled"); + + BString warning = ""; + warning << "Save changse to'"; + warning << nameBuffer; + warning << "' before closing?"; + + BAlert* alert = new BAlert("Save", warning.String(), + "Cancel", "Don't save", "Save", + B_WIDTH_AS_USUAL, B_OFFSET_SPACING, B_WARNING_ALERT); + + alert->SetShortcut(0, B_ESCAPE); + + int32 result = alert->Go(); + + switch (result) { + case 0: + return false; + case 1: + goto quit; + case 2: + { + _Save(); + + if (fUnsavedChanges) + return false; + else + goto quit; + } + } + } + + quit: + BMessage* msg = new BMessage(MSG_CLOSE); + msg->AddPointer("window", (void*)this); + be_app->PostMessage(msg); + return true; +} + + +void +MainWindow::SelectionChanged() +{ + if (fResourceList->CurrentSelection(NULL) == NULL) { + fMoveUpButton->SetEnabled(false); + fMoveDownButton->SetEnabled(false); + fRemoveButton->SetEnabled(false); + + fCutItem->SetEnabled(false); + fCopyItem->SetEnabled(false); + } else { + fRemoveButton->SetEnabled(true); + fMoveUpButton->SetEnabled(!fResourceList->RowAt(0)->IsSelected()); + fMoveDownButton->SetEnabled(!fResourceList->RowAt( + fResourceList->CountRows() - 1)->IsSelected()); + + fCutItem->SetEnabled(true); + fCopyItem->SetEnabled(true); + } +} + + +void +MainWindow::MouseDown(BPoint point) +{ + +} + + +void +MainWindow::MessageReceived(BMessage* msg) +{ + switch (msg->what) { + case MSG_NEW: + be_app->PostMessage(MSG_NEW); + break; + + case MSG_OPEN: + be_app->PostMessage(MSG_OPEN); + break; + + case MSG_CLOSE: + PostMessage(B_QUIT_REQUESTED); + break; + + case MSG_SAVE: + _Save(); + break; + + case MSG_SAVEAS: + _SaveAs(); + break; + + case MSG_SAVEAS_DONE: + { + entry_ref ref; + const char* leaf; + + if (msg->FindRef("directory", &ref) != B_OK) + break; + + if (msg->FindString("name", &leaf) != B_OK) + break; + + BDirectory dir(&ref); + _Save(new BEntry(&dir, leaf)); + + break; + } + case MSG_SAVEALL: + be_app->PostMessage(MSG_SAVEALL); + break; + + case MSG_MERGEWITH: + PRINT(("[MSG_MERGEWITH]: Not yet implemented.")); + // TODO: Implement. + // "Merge from..." might be a better idea actually. + break; + + case MSG_QUIT: + be_app->PostMessage(B_QUIT_REQUESTED); + break; + + case MSG_UNDO: + fUndoContext->Undo(); + _RefreshUndoRedo(); + break; + + case MSG_REDO: + fUndoContext->Redo(); + _RefreshUndoRedo(); + break; + + case MSG_CUT: + // TODO: Implement. + PRINT(("[MSG_CUT]: Not yet implemented.")); + break; + + case MSG_COPY: + // TODO: Implement. + PRINT(("[MSG_COPY]: Not yet implemented.")); + break; + + case MSG_PASTE: + // TODO: Implement. + PRINT(("[MSG_PASTE]: Not yet implemented.")); + break; + + case MSG_CLEAR: + { + BList* rows = new BList(); + + for (int32 i = 0; i < fResourceList->CountRows(); i++) { + ResourceRow* row = (ResourceRow*)fResourceList->RowAt(i); + row->ActionIndex = i; + rows->AddItem(row); + } + + _Do(new RemoveAction("Clear", fResourceList, rows)); + + SelectionChanged(); + break; + } + case MSG_SELECTALL: + { + for (int32 i = 0; i < fResourceList->CountRows(); i++) + fResourceList->AddToSelection(fResourceList->RowAt(i)); + + SelectionChanged(); + break; + } + case MSG_SETTINGS: + be_app->PostMessage(MSG_SETTINGS); + break; + + case MSG_ADD: + { + // Thank you, François Claus :D Merry Christmas! + + int32 ix = fResourceTypePopUp->FindMarkedIndex(); + + if (ix != -1) { + BList* rows = new BList(); + + ResourceRow* row = new ResourceRow(); + row->SetResourceID(_NextResourceID()); + row->SetResourceType(kDefaultTypes[ix].type); + row->SetResourceStringCode(kDefaultTypes[ix].code); + row->SetResourceData(kDefaultTypes[ix].data); + row->SetResourceSize(kDefaultTypes[ix].size); + row->ActionIndex = fResourceList->CountRows(NULL); + + rows->AddItem(row); + + _Do(new AddAction("Add", fResourceList, rows)); + } + + break; + } + case MSG_REMOVE: + { + BList* rows = new BList(); + + for (int i = 0; i < fResourceList->CountRows(); i++) { + ResourceRow* row = (ResourceRow*)fResourceList->RowAt(i); + + if (row->IsSelected()) { + row->ActionIndex = i; + rows->AddItem(row); + } + } + + if (!rows->IsEmpty()) + _Do(new RemoveAction("Remove", fResourceList, rows)); + else + delete rows; + + break; + } + case MSG_MOVEUP: + { + BList* rows = new BList(); + + for (int i = 1; i < fResourceList->CountRows(); i++) { + ResourceRow* row = (ResourceRow*)fResourceList->RowAt(i); + + if (row->IsSelected()) { + row->ActionIndex = i; + rows->AddItem(row); + } + } + + _Do(new MoveUpAction("Move Up", fResourceList, rows)); + + break; + } + case MSG_MOVEDOWN: + { + BList* rows = new BList(); + + for (int i = 0; i < fResourceList->CountRows() - 1; i++) { + ResourceRow* row = (ResourceRow*)fResourceList->RowAt(i); + + if (row->IsSelected()) { + row->ActionIndex = i; + rows->AddItem(row); + } + } + + _Do(new MoveDownAction("Move Down", fResourceList, rows)); + + break; + } + case MSG_SELECTION: + SelectionChanged(); + break; + + case MSG_INVOCATION: + { + BRect frame = Frame(); + + new EditWindow(BRect(frame.left + 50, frame.top + 50, + frame.left + 300, frame.top + 350), + (ResourceRow*)fResourceList->CurrentSelection()); + + break; + } + case MSG_SETTINGS_APPLY: + AdaptSettings(); + break; + + default: + BWindow::MessageReceived(msg); + } +} + + +void +MainWindow::AdaptSettings() +{ + fUndoContext->SetLimit(fSettings->UndoLimit); +} + + +void +MainWindow::_SetTitleFromEntry() +{ + char nameBuffer[B_FILE_NAME_LENGTH]; + + fAssocEntry->GetName(nameBuffer); + + BString title; + title << "ResourceEdit | "; + title << nameBuffer; + SetTitle(title); +} + + +void +MainWindow::_SaveAs() +{ + if (fSavePanel == NULL) + fSavePanel = new BFilePanel(B_SAVE_PANEL, new BMessenger(this), NULL, + B_FILE_NODE, false, new BMessage(MSG_SAVEAS_DONE)); + + fSavePanel->Rewind(); + fSavePanel->Show(); +} + + +void +MainWindow::_Save(BEntry* entry) +{ + if (entry == NULL) { + if (fAssocEntry == NULL) { + _SaveAs(); + return; + } else + entry = fAssocEntry; + } else { + if (fAssocEntry == NULL) { + fAssocEntry = entry; + _SetTitleFromEntry(); + } + } + + BPath path; + entry->GetPath(&path); + + // I wouldn't use std:: if BFile had cooler stuff. + // Not very comfortable here. + + fstream out(path.Path(), ios::out); + + time_t timeNow = time(0); + + + out << "/*" << endl; + out << " * This file is auto-generated by Haiku ResourceEdit." << endl; + out << " * Time: " << ctime((const time_t*)&timeNow); + out << " */" << endl; + + for (int32 i = 0; i < fResourceList->CountRows(); i++) { + ResourceRow* row = (ResourceRow*)fResourceList->RowAt(i); + + out << endl; + out << "resource"; + + if (row->ResourceStringID()[0] != '\0') { + out << "(" << row->ResourceID(); + + if (row->ResourceName()[0] != '\0') + out << ", \"" << row->ResourceName() << "\""; + + out << ")"; + } else { + if (row->ResourceName()[0] != '\0') + out << "(\"" << row->ResourceName() << "\")"; + } + + out << " "; + + if (row->ResourceStringCode()[0] != '\0') + out << "#\'" << row->ResourceStringCode() << "\' "; + + if (strcmp(row->ResourceType(), "raw") != 0) + out << row->ResourceType() << ' ' << row->ResourceData(); + else { + // TODO: Implement hexdump and import. + out << "array {" << endl; + out << "\t\"Not yet implemented.\"" << endl; + out << "}"; + } + + out << ";" << endl; + } + + out.close(); + + // Killed code: Export to .rsrc + + /*BFile* file = new BFile(entry, B_READ_WRITE | B_CREATE_FILE); + BResources output(file, true); + delete file; + + for (int32 i = 0; i < fResourceList->CountRows(); i++) { + ResourceRow* row = (ResourceRow*)fResourceList->RowAt(i); + + output.AddResource(row->ResourceCode(), row->ResourceID(), + row->ResourceRawData(), row->ResourceSize(), row->ResourceName()); + } + + output.Sync();*/ + + fUnsavedChanges = false; +} + + +void +MainWindow::_Load() +{ + // CAUTION: Here be dragons. + + // [Initialization phase] + + BPath path; + struct stat st; + + fAssocEntry->GetPath(&path); + fAssocEntry->GetStat(&st); + + int fd = open(path.Path(), 0); + + const char* in = (const char*)mmap(NULL, st.st_size, PROT_READ, + MAP_SHARED, fd, 0); + + // [Setup phase] + + enum { + T_STATE_NORMAL, + T_STATE_COMMENT, + T_STATE_MULTILINE_COMMENT, + T_STATE_STRING, + } t_state = T_STATE_NORMAL; + + char quoteType = '\0'; + + char escChars[256]; + + for (int32 i = 0; i < 256; i++) + escChars[i] = ~(char)0; + + escChars['n'] = '\n'; + escChars['t'] = '\t'; + escChars['r'] = '\r'; + escChars['0'] = '\0'; + escChars['"'] = '\"'; + escChars['\'']= '\''; + + // TODO: Add other escape sequences? + // Multichar escape sequences cannot be resolved with this. + + BString buffer = ""; + BList* tokens = new BList(); + + BList* errors = new BList(); + // Multiple errors are allowed, but currently unused. + + BList* rows = new BList(); + + // [Tokenization phase] + + for (int32 i = 0; i < st.st_size - 1; i++) { + if (t_state == T_STATE_NORMAL) { + if (in[i] == ' ' || in[i] == '\t' || in[i] == '\n' + || in[i] == '\r') { + + if (buffer != "") { + tokens->AddItem(new BString(buffer)); + buffer = ""; + } + + continue; + } + + if (in[i] == ',' || in[i] == ';' || in[i] == '{' || in[i] == '}' + || in[i] == '(' || in[i] == ')') { + if (buffer != "") { + tokens->AddItem(new BString(buffer)); + buffer = in[i]; + tokens->AddItem(new BString(buffer)); + buffer = ""; + } + + continue; + } + + if (in[i] == '"' || in[i] == '\'') { + t_state = T_STATE_STRING; + quoteType = in[i]; + buffer += in[i]; + continue; + } + + if (in[i] == '/') { + if (in[i + 1] == '/') { + t_state = T_STATE_COMMENT; + continue; + } + + if (in[i + 1] == '*') { + t_state = T_STATE_MULTILINE_COMMENT; + continue; + } + } + + buffer += in[i]; + + } else if (t_state == T_STATE_COMMENT) { + if (in[i] == '\n') { + t_state = T_STATE_NORMAL; + continue; + } + } else if (t_state == T_STATE_MULTILINE_COMMENT) { + if (in[i] == '*' && in[i + 1] == '/') { + t_state = T_STATE_NORMAL; + i++; + continue; + } + } else if (t_state == T_STATE_STRING) { + if (in[i] == '\\' && escChars[(int)in[i]] != ~(char)0) { + buffer += escChars[(int)in[i]]; + i++; + continue; + } + + if (in[i] == quoteType) { + buffer += in[i]; + tokens->AddItem(new BString(buffer)); + buffer = ""; + t_state = T_STATE_NORMAL; + continue; + } + + buffer += in[i]; + } else { + // This can't even happen. + } + } + + if (t_state == T_STATE_MULTILINE_COMMENT) + errors->AddItem(new BString( + "Multi-line comment not closed by end of file.")); + else if (t_state == T_STATE_STRING) + errors->AddItem(new BString("String not closed by end of file.")); + else { + // [Parsing phase] + + for (int32 i = 0; i < tokens->CountItems(); i++) { + BString& token = *(BString*)tokens->ItemAt(i); + + if (token == "resource") { + ResourceRow* row = new ResourceRow(); + + token = *(BString*)tokens->ItemAt(++i); + + if (token[0] == '(') { + BList args; + bool wantComma = false; + + while (true) { + token = *(BString*)tokens->ItemAt(++i); + + if (token[0] == ')') + break; + + if (wantComma) { + if (token[0] != ',') { + errors->AddItem(new BString("Expected ','.")); + break; + } + + wantComma = false; + } else { + args.AddItem(tokens->ItemAt(i)); + wantComma = true; + } + } + + if (errors->CountItems() > 0) + break; + + token = *(BString*)tokens->ItemAt(++i); + + if (args.CountItems() > 2) { + errors->AddItem(new BString( + "Too many arguments for resource identifier.")); + break; + } + + if (args.CountItems() >= 1) { + BString& arg = *(BString*)args.ItemAt(0); + + if (arg[0] == '"') { + errors->AddItem(new BString( + "Resource ID cannot be a string.")); + break; + } + + row->SetResourceStringID(arg); + } + + if (args.CountItems() == 2) { + BString& arg = *(BString*)args.ItemAt(1); + + if (arg[0] != '"') { + errors->AddItem(new BString( + "Resource name must be a string.")); + break; + } + + row->SetResourceName(arg); + } + } + + if (token[0] == '#') { + if (token.Length() != 7 + || token[1] != '\'' || token[6] != '\'') { + errors->AddItem(new BString( + "Invalid syntax for resource type-code.")); + break; + } + + BString code; + token.CopyInto(code, 2, 4); + row->SetResourceStringCode(code); + + token = *(BString*)tokens->ItemAt(++i); + } + + if (token[0] == '(') { + BString& type = *(BString*)tokens->ItemAt(++i); + token = *(BString*)tokens->ItemAt(++i); + + if (token[0] != ')') { + errors->AddItem(new BString( + "Expected ')'.")); + break; + } + + row->SetResourceType(type); + } + + } else if (token == "type") { + // TODO: Implement. + } else if (token == "enum") { + // TODO: Implement. + } + } + } + + // [Result phase] + + if (errors->CountItems() > 0) { + for (int32 i = 0; i < errors->CountItems(); i++) { + BString& error = *(BString*)errors->ItemAt(i); + PRINT(("ERROR: %s\n", error.String())); + delete (BString*)tokens->ItemAt(i); + } + + delete errors; + } else { + for (int32 i = 0; i < rows->CountItems(); i++) { + ResourceRow* row = (ResourceRow*)rows->ItemAt(i); + PRINT(("[Resource]\n")); + PRINT(("id = %s\n", row->ResourceStringID())); + PRINT(("name = %s\n", row->ResourceName())); + // ... + PRINT(("\n")); + } + } + + // [Cleanup phase] + + for (int32 i = 0; i < tokens->CountItems(); i++) + delete (BString*)tokens->ItemAt(i); + + delete tokens; + + munmap((void*)in, st.st_size); + + // Killed code: Import from .rsrc + + /*BFile* file = new BFile(fAssocEntry, B_READ_ONLY); + BResources input(file); + delete file; + + type_code code; + int32 id; + const char* name; + size_t size; + + for (int32 i = 0; input.GetResourceInfo(i, &code, &id, &name, &size); i++) { + ResourceRow* row = new ResourceRow(); + row->SetResourceID(id); + row->SetResourceName(name); + row->SetResourceSize(size); + row->SetResourceCode(code); + row->SetResourceRawData(input.LoadResource(code, id, &size)); + fResourceList->AddRow(row); + }*/ +} + + +int32 +MainWindow::_NextResourceID() +{ + int32 currentID = atoi(fResourceIDText->Text()); + int32 nextID = currentID + 1; + BString text; + + // Should I check if the ID is already present in the list? + // Hmmm... + + text << nextID; + fResourceIDText->SetText(text); + + return currentID; +} + + +void +MainWindow::_RefreshStats() +{ + const size_t kB = 1024; + const size_t MB = 1024 * 1024; + const size_t GB = 1024 * 1024 * 1024; + + size_t size = 0; + + BString text = ""; + + text << fResourceList->CountRows(); + text << " resources, "; + + for (int32 i = 0; i < fResourceList->CountRows(); i++) { + ResourceRow* row = (ResourceRow*)fResourceList->RowAt(i); + size += row->ResourceSize(); + } + + if (size >= GB) { + text << (double)size / GB; + text << " GB"; + } else if (size >= MB) { + text << (double)size / MB; + text << " MB"; + } else if (size >= kB) { + text << (double)size / kB; + text << " kB"; + } else { + text << size; + text << " bytes"; + } + + fStatsString->SetText(text); +} + + +void +MainWindow::_RefreshUndoRedo() +{ + if (fUndoContext->CanUndo()) { + fUndoItem->SetEnabled(true); + fUndoItem->SetLabel(fUndoContext->UndoLabel().Prepend("Undo ")); + } else { + fUndoItem->SetEnabled(false); + fUndoItem->SetLabel("Undo"); + } + + if (fUndoContext->CanRedo()) { + fRedoItem->SetEnabled(true); + fRedoItem->SetLabel(fUndoContext->RedoLabel().Prepend("Redo ")); + } else { + fRedoItem->SetEnabled(false); + fRedoItem->SetLabel("Redo"); + } +} + + +void +MainWindow::_Do(UndoContext::Action* action) +{ + fUnsavedChanges = true; + fUndoContext->Do(action); + _RefreshStats(); + _RefreshUndoRedo(); +} + + +MainWindow::AddAction::AddAction(const BString& label, + ResourceListView* list, BList* rows) + : + UndoContext::Action(label) +{ + fList = list; + fRows = rows; + fAdded = false; +} + + +MainWindow::AddAction::~AddAction() +{ + if (!fAdded) + for (int32 i = 0; i < fRows->CountItems(); i++) + delete (ResourceRow*)fRows->ItemAt(i); + + delete fRows; +} + + +void +MainWindow::AddAction::Do() +{ + for (int32 i = 0; i < fRows->CountItems(); i++) { + ResourceRow* row = (ResourceRow*)fRows->ItemAt(i); + fList->AddRow(row, row->ActionIndex, row->Parent); + } + + fAdded = true; +} + + +void +MainWindow::AddAction::Undo() +{ + for (int32 i = 0; i < fRows->CountItems(); i++) + fList->RemoveRow((ResourceRow*)fRows->ItemAt(i)); + + fAdded = false; +} + + +MainWindow::RemoveAction::RemoveAction(const BString& label, + ResourceListView* list, BList* rows) + : + UndoContext::Action(label) +{ + fList = list; + fRows = rows; + fRemoved = false; +} + + +MainWindow::RemoveAction::~RemoveAction() +{ + if (fRemoved) + for (int32 i = 0; i < fRows->CountItems(); i++) + delete (ResourceRow*)fRows->ItemAt(i); + + delete fRows; +} + + +void +MainWindow::RemoveAction::Do() +{ + for (int32 i = 0; i < fRows->CountItems(); i++) + fList->RemoveRow((ResourceRow*)fRows->ItemAt(i)); + + fRemoved = true; +} + + +void +MainWindow::RemoveAction::Undo() +{ + for (int32 i = 0; i < fRows->CountItems(); i++) { + ResourceRow* row = (ResourceRow*)fRows->ItemAt(i); + + fList->AddRow(row, row->ActionIndex, row->Parent); + } + + fRemoved = false; +} + +// TODO: Implement EditAction + +MainWindow::MoveUpAction::MoveUpAction(const BString& label, + ResourceListView* list, BList* rows) + : + UndoContext::Action(label) +{ + fList = list; + fRows = rows; +} + + +MainWindow::MoveUpAction::~MoveUpAction() +{ + delete fRows; +} + + +void +MainWindow::MoveUpAction::Do() +{ + for (int32 i = 0; i < fRows->CountItems(); i++) { + ResourceRow* row = (ResourceRow*)fRows->ItemAt(i); + + fList->SwapRows(row->ActionIndex, row->ActionIndex - 1, + row->Parent, row->Parent); + + row->ActionIndex--; + } + + fList->SelectionChanged(); +} + + +void +MainWindow::MoveUpAction::Undo() +{ + for (int32 i = fRows->CountItems() - 1; i >= 0; i--) { + ResourceRow* row = (ResourceRow*)fRows->ItemAt(i); + + fList->SwapRows(row->ActionIndex, row->ActionIndex + 1, + row->Parent, row->Parent); + + row->ActionIndex++; + } + + fList->SelectionChanged(); +} + +MainWindow::MoveDownAction::MoveDownAction(const BString& label, + ResourceListView* list, BList* rows) + : + UndoContext::Action(label) +{ + fList = list; + fRows = rows; +} + + +MainWindow::MoveDownAction::~MoveDownAction() +{ + delete fRows; +} + + +void +MainWindow::MoveDownAction::Do() +{ + for (int32 i = fRows->CountItems() - 1; i >= 0; i--) { + ResourceRow* row = (ResourceRow*)fRows->ItemAt(i); + + fList->SwapRows(row->ActionIndex, row->ActionIndex + 1, + row->Parent, row->Parent); + + row->ActionIndex++; + } + + fList->SelectionChanged(); +} + + +void +MainWindow::MoveDownAction::Undo() +{ + for (int32 i = 0; i < fRows->CountItems(); i++) { + ResourceRow* row = (ResourceRow*)fRows->ItemAt(i); + + fList->SwapRows(row->ActionIndex, row->ActionIndex - 1, + row->Parent, row->Parent); + + row->ActionIndex--; + } + + fList->SelectionChanged(); +} + diff --git a/src/apps/resourceedit/MainWindow.h b/src/apps/resourceedit/MainWindow.h new file mode 100644 index 0000000000..b903e1ef7a --- /dev/null +++ b/src/apps/resourceedit/MainWindow.h @@ -0,0 +1,186 @@ +/* + * Copyright 2012-2013 Tri-Edge AI + * All rights reserved. Distributed under the terms of the MIT license. + */ +#ifndef MAIN_WINDOW_H +#define MAIN_WINDOW_H + + +#include "UndoContext.h" + +#include + + +class ImageButton; +class ResourceListView; +class ResourceRow; +class SettingsFile; + +class BBox; +class BEntry; +class BFilePanel; +class BMenu; +class BMenuBar; +class BMenuField; +class BMenuItem; +class BMessage; +class BPopUpMenu; +class BStringView; +class BTextControl; + + +class MainWindow : public BWindow { +public: + MainWindow(BRect frame, BEntry* entry, SettingsFile* settings); + ~MainWindow(); + + bool QuitRequested(); + void MouseDown(BPoint point); + void MessageReceived(BMessage* msg); + void SelectionChanged(); + + void AdaptSettings(); + +private: + BEntry* fAssocEntry; + SettingsFile* fSettings; + + BFilePanel* fSavePanel; + bool fUnsavedChanges; + + UndoContext* fUndoContext; + + BMenuBar* fMenuBar; + + BMenu* fFileMenu; + BMenuItem* fNewItem; + BMenuItem* fOpenItem; + BMenuItem* fCloseItem; + BMenuItem* fSaveItem; + BMenuItem* fSaveAsItem; + BMenuItem* fSaveAllItem; + BMenuItem* fMergeWithItem; + BMenuItem* fQuitItem; + + BMenu* fEditMenu; + BMenuItem* fUndoItem; + BMenuItem* fRedoItem; + BMenuItem* fCutItem; + BMenuItem* fCopyItem; + BMenuItem* fPasteItem; + BMenuItem* fClearItem; + BMenuItem* fSelectAllItem; + + BMenu* fToolsMenu; + BMenuItem* fAddAppResourcesItem; + BMenuItem* fSettingsItem; + + BMenu* fHelpMenu; + + BTextControl* fResourceIDText; + BPopUpMenu* fResourceTypePopUp; + BMenuField* fResourceTypeMenu; + + BView* fToolbarView; + ImageButton* fAddButton; + ImageButton* fRemoveButton; + ImageButton* fMoveUpButton; + ImageButton* fMoveDownButton; + + ResourceListView* fResourceList; + BBox* fStatsBox; + BStringView* fStatsString; + + void _SetTitleFromEntry(); + void _SaveAs(); + void _Save(BEntry* entry = NULL); + void _Load(); + + int32 _NextResourceID(); + + void _RefreshStats(); + void _RefreshUndoRedo(); + void _Do(UndoContext::Action* action); + + class AddAction : public UndoContext::Action { + public: + AddAction(const BString& label, + ResourceListView* list, BList* rows); + ~AddAction(); + + void Do(); + void Undo(); + + private: + ResourceListView* fList; + BList* fRows; + bool fAdded; + + }; + + class RemoveAction : public UndoContext::Action { + public: + RemoveAction(const BString& label, + ResourceListView* list, BList* rows); + ~RemoveAction(); + + void Do(); + void Undo(); + + private: + ResourceListView* fList; + BList* fRows; + bool fRemoved; + + }; + + class EditAction : public UndoContext::Action { + public: + EditAction(const BString& label, + ResourceListView* list, + ResourceRow* rowold, ResourceRow* rownew); + ~EditAction(); + + void Do(); + void Undo(); + + private: + ResourceListView* fList; + ResourceRow* fRowOld; + ResourceRow* fRowNew; + + }; + + class MoveUpAction : public UndoContext::Action { + public: + MoveUpAction(const BString& label, + ResourceListView* list, BList* rows); + ~MoveUpAction(); + + void Do(); + void Undo(); + + private: + ResourceListView* fList; + BList* fRows; + + }; + + class MoveDownAction : public UndoContext::Action { + public: + MoveDownAction(const BString& label, + ResourceListView* list, BList* rows); + ~MoveDownAction(); + + void Do(); + void Undo(); + + private: + ResourceListView* fList; + BList* fRows; + + }; +}; + + +#endif diff --git a/src/apps/resourceedit/ResourceEdit.cpp b/src/apps/resourceedit/ResourceEdit.cpp new file mode 100644 index 0000000000..977e463797 --- /dev/null +++ b/src/apps/resourceedit/ResourceEdit.cpp @@ -0,0 +1,152 @@ +/* + * Copyright 2012-2013 Tri-Edge AI + * All rights reserved. Distributed under the terms of the MIT license. + */ + + +#include "ResourceEdit.h" + +#include "AboutWindow.h" +#include "Constants.h" +#include "MainWindow.h" +#include "SettingsFile.h" +#include "SettingsWindow.h" + +#include +#include + + +ResourceEdit::ResourceEdit() + : + BApplication("application/x-vnd.Haiku-ResourceEdit") +{ + fCascade = BRect(100, 100, 700, 400); + fCascadeCount = 0; + + fOpenPanel = new BFilePanel(B_OPEN_PANEL, &be_app_messenger, NULL, 0, true, + new BMessage(MSG_OPEN_DONE)); + + fSettings = new SettingsFile("resourceedit_settings"); + fSettings->Load(); + + fSettingsWindow = NULL; +} + + +ResourceEdit::~ResourceEdit() +{ + +} + + +void +ResourceEdit::MessageReceived(BMessage* msg) +{ + switch (msg->what) { + case MSG_NEW: + _CreateWindow(NULL); + break; + + case MSG_OPEN: + fOpenPanel->Show(); + break; + + case MSG_OPEN_DONE: + { + entry_ref ref; + + while (fOpenPanel->GetNextSelectedRef(&ref) == B_OK) + _CreateWindow(new BEntry(&ref)); + + fOpenPanel->Rewind(); + + break; + } + case MSG_CLOSE: + { + MainWindow* window; + msg->FindPointer("window", (void**)&window); + fWindowList.RemoveItem(window); + + if (fWindowList.CountItems() == 0) + Quit(); + + break; + } + case MSG_SAVEALL: + { + for (int32 i = 0; i < fWindowList.CountItems(); i++) { + MainWindow* window = ((MainWindow*)fWindowList.ItemAt(i)); + window->PostMessage(MSG_SAVE); + } + + break; + } + case MSG_SETTINGS: + { + if (fSettingsWindow != NULL) + fSettingsWindow->Activate(); + else + fSettingsWindow = new SettingsWindow(fSettings); + + break; + } + case MSG_SETTINGS_APPLY: + { + for (int32 i = 0; i < fWindowList.CountItems(); i++) { + MainWindow* window = ((MainWindow*)fWindowList.ItemAt(i)); + window->PostMessage(MSG_SETTINGS_APPLY); + } + + break; + } + case MSG_SETTINGS_CLOSED: + fSettingsWindow = NULL; + break; + + default: + BApplication::MessageReceived(msg); + } +} + + +void +ResourceEdit::ArgvReceived(int32 argc, char* argv[]) +{ + for (int32 i = 1; i < argc; i++) + _CreateWindow(new BEntry(argv[i])); +} + + +void +ResourceEdit::ReadyToRun() +{ + if (fWindowList.CountItems() <= 0) + _CreateWindow(NULL); +} + + +void +ResourceEdit::_CreateWindow(BEntry* assocEntry) +{ + MainWindow* window = new MainWindow(_Cascade(), assocEntry, fSettings); + + fWindowList.AddItem(window); + + window->Show(); +} + + +BRect +ResourceEdit::_Cascade() +{ + if (fCascadeCount == 8) { + fCascade.OffsetBy(-20 * 8, -20 * 8); + fCascadeCount = 0; + } else { + fCascade.OffsetBy(20, 20); + fCascadeCount++; + } + + return fCascade; +} diff --git a/src/apps/resourceedit/ResourceEdit.h b/src/apps/resourceedit/ResourceEdit.h new file mode 100644 index 0000000000..6168fcfc2c --- /dev/null +++ b/src/apps/resourceedit/ResourceEdit.h @@ -0,0 +1,47 @@ +/* + * Copyright 2012-2013 Tri-Edge AI + * All rights reserved. Distributed under the terms of the MIT license. + */ +#ifndef RESOURCE_EDIT_H +#define RESOURCE_EDIT_H + + +#include + + +class MainWindow; +class SettingsFile; +class SettingsWindow; + +class BEntry; +class BFilePanel; +class BMessage; + + +class ResourceEdit : public BApplication { +public: + ResourceEdit(); + ~ResourceEdit(); + + void MessageReceived(BMessage* msg); + +private: + BRect fCascade; + uint32 fCascadeCount; + BList fWindowList; + + BFilePanel* fOpenPanel; + + SettingsFile* fSettings; + SettingsWindow* fSettingsWindow; + + void ArgvReceived(int32 argc, char* argv[]); + void ReadyToRun(); + + void _CreateWindow(BEntry* assocEntry); + BRect _Cascade(); + +}; + + +#endif diff --git a/src/apps/resourceedit/ResourceEdit.rdef b/src/apps/resourceedit/ResourceEdit.rdef new file mode 100644 index 0000000000..c225980220 --- /dev/null +++ b/src/apps/resourceedit/ResourceEdit.rdef @@ -0,0 +1,136 @@ +resource app_signature "application/x-vnd.Haiku-ResourceEdit"; + +resource app_name_catalog_entry "x-vnd.Haiku-ResourceEdit:System name:ResourceEdit"; + +resource app_version { + major = 0, + middle = 1, + minor = 0, + + variety = B_APPV_ALPHA, + internal = 0, + + short_info = "ResourceEdit", + long_info = "ResourceEdit © 2012-2013 Haiku, Inc." +}; + +resource app_flags B_SINGLE_LAUNCH; + +resource file_types message { + "types" = "text/x-vnd.Be.ResourceDef" +}; + +resource vector_icon { + $"6E6369660E050102000603399E0F3D9C0ABF82B23B84A94B88504870C900A5FF" + $"F5BCEAFFF2FFB3FFE3020106023E49240000000000003CAAAA4940004A3000FF" + $"C0FFDD7C6DFFBC040192020006023A4BAE3411A9B629883C6629495368484715" + $"00FFF9BAFFFFC104020006023A6A0E3670BCB6D8C13AD0F64A21BC4A0DF300BA" + $"DCFFFF2A20F10200060239AAD5343BA5B6E7993C629D4ABB354803A500E99797" + $"FFCE323202000602AAB1FB3A081FBE8A26AF5E794C4014448D43FFFDDCAB00DB" + $"AB5F02000602B507E13A82E2BAD599B56BB44A7652479FE400116201FE69A403" + $"020006023C08200000000000004000004A4000000000FD6AD839004AB9270200" + $"06023D4D340000000000004000004A5000000000009CFA80FFF8FAFF02000603" + $"B2F679BA14D43A7FB6B38E9E460F5547105A00FFEED58DDBAB5FCFFFEED50401" + $"95020012023B8E380000000000004000004A5400C100000001FFFF0199120606" + $"AE0BB40BBF4D33C3AFB75DC173BDEFC607C13EC804CA28BD82C118B920C51BBB" + $"40BF07B8083AB6BC0605AE02B57D3EB9B9C3EFB7BB44BBB751BD75C936CA8EC1" + $"B1402F0A093B593D5BBFCDC93E455BC516C5F160465B435D4544510A045A425E" + $"3F5A3D57400A063236323D3A41403E403739330A063A433A4A404D464A464341" + $"400A064237423E48424E3F4E3948350604EE532755295528552A532B5229522A" + $"52280604EE532456295625562D532E5029502D50250A04B969B771332E502E4E" + $"2B0A04B969B5BAB969B7714E2B4E270A043324B969B5BA4E2750240A063124B8" + $"BAB5B2B8BAB779312EB677B6ECB67CB63C0606B20831245356295625562D532E" + $"3126290804BA28B4D33027302BBA28B8580003C6E8B4D3C6E8B4D3C690B51750" + $"2950B59E50B78DC6E8B858C690B814C6E8B8580A04C6F0C5C24E4F514BC9BBC4" + $"280A06C4E04F41C507374B394A45C33CC6D1C36F120A030202032020250A0001" + $"0130202501178400040A0201012020250A00010030202501178400040A010100" + $"2020250A000304050630202501178400040A0401042020250A0501052020250A" + $"0601062020250A0C0110000A0D0111000A00030D0E0F123ED413BED4133ED413" + $"3ED41347F4A24A588901178400040A0B010C023ED413BED4133ED4133ED41347" + $"F4A24A58890A0A010B023ED413BED4133ED4133ED41347F4A24A58890A09010A" + $"023ED413BED4133ED4133ED41347F4A24A58890A080109023ED413BED4133ED4" + $"133ED41347F4A24A58890A070108023ED413BED4133ED4133ED41347F4A24A58" + $"890A0001070A3ED413BED4133ED4133ED41347F4A24A588915FF" +}; + +resource(1, "add.png") #'PNG ' array { + $"89504E470D0A1A0A0000000D4948445200000018000000180806000000E0773D" + $"F80000017B494441544889ED95B14EC25014863F6AAB4864C40768D84C184908" + $"3E002B899B71742171C7677024716572C207707124260C0E460709A94C86844D" + $"144BEF6D716841CA2D5083C6857FBB7FFE73BF7B4F7B5AD8E8BF9588952A5231" + $"0B660D1D0D008967DD59559A5CAC2AD56301D2E473A739CDD8330010EF42B31E" + $"AD32D000BAEB03005BDA48210190524EEC9D5575B1011FCE07C676700347C42D" + $"8B0F1042E0391E00AE70D70014A990261FF2521C0EE5105DF8712925A4C852A2" + $"0EB4A7B9012D9A5CCE96AA6FD119AE79646AF3B6B16B7CA7C7203ED53659D796" + $"478D1CF0B4F8060934477714DB11735E54731368C0FE72C018466214511D4363" + $"D5520112AFFFD6575A4492508BB02300126F35E0812A2F94435E8A2CC7644806" + $"6B1BB8A2CF904E2837A00B61880AF0C7BFC1EC1095A8E3929996BAC0900E379C" + $"03BDB91D5E97037C75E7D66DA01091EB01CF0BF60040EDF52FEBCF01F13E1503" + $"5ADC72C2567020172F78A02B15EF7FE0EB007F8826F2807B60F0833D3652F505" + $"AA6A764F51A11AA20000000049454E44AE426082" +}; + +resource(2, "remove.png") #'PNG ' array { + $"89504E470D0A1A0A0000000D4948445200000018000000180806000000E0773D" + $"F800000275494441544889ED94C14B93611CC73F7B7D6DF80EDA72BEAFCE2D82" + $"57F022099AE065902884791C41052BD7FE804DA48378AF4E49978E199845273D" + $"CC90C0759B78085C66186387053A9C4B3417CB4DD6D3C136F5F5DDC04E1DFCC2" + $"0F5E9EDFFB7EBEBFEFFB3CEF0BE7FA6FA5C3C551557D1780A78064728B148027" + $"A3AAFA5E07C799E1E31ECFC7642824627EBF08C282C1440AC2B398DF2F92A190" + $"18F778523A38CD587566F03BAAFA617868E85A8BA2D06CB3E172B974CBDA9A77" + $"19A6014B10261EF87CE14EB71B9B24D1E6763B4AEBEBB737F2F9573BF0ABA6C1" + $"B0AACE04FBFBAF373734208A4544B188A628B8344D9792496F17740D0F0E86AF" + $"B6B454FA3649A2ADB5D5F1736BEBE6523EFF02289579B2D160379BFDBA99C90C" + $"A986F50EBB9D7B7D7D03C04087DD4E696FEF447F339361379BDD00BA81A5AA09" + $"E2B050974A793545D1554942140A9552651955964FAC894281CFE934D38B8BD1" + $"97F01A5804F6AB1A006219A6E574DAAB59AD7A932C230E0EAAD66A26C39B783C" + $"3A09534004D8A9B907C74DEAB359AF2ACB7A9310A7A61685025FB6B7799B4854" + $"8583C91E18B42A72B9815295A6C8E5CA977366F05A09A4204CDC8270BBCD5639" + $"2DC67202CDF9BC6E859EBF47581841966A701F84DB6BA7AB2801CC4074126E00" + $"BF6B2608C0631F3C348327806D4E7FB24E4003DD0ABDF1C3937434AD11E280EE" + $"C62AF05988CE423461D26F3C7CD60D74D64CB00573F570F7323814037C12A696" + $"E15103F468A097937C0722F06D069EEFC027E087C90C47D2C13906A918880894" + $"7F76F7814BE5E44158888088811883940E21A0AD26D86832022B019837C0CB92" + $"02303F022B67861FD305A0D7045E9685C3777EE55FE0E702E00F037E0BAE5DFC" + $"3C830000000049454E44AE426082" +}; + +resource(3, "moveup.png") #'PNG ' array { + $"89504E470D0A1A0A0000000D4948445200000018000000180806000000E0773D" + $"F8000001C8494441544889ED933B485B6118861F93D8788F510E27DAE00D259D" + $"0485823108723843296E22850E0EBA140AA543C4A18A9442A920EA62068582E2" + $"E0AA83E2050415A18B882028ED927AE8693C31510721A8F93B5841E9C9498A2E" + $"822FBCC3CFF7F3BCDFF75FE0510F465EC81E57F93AAE32ED85EC7B854B609F50" + $"98D4D755A1AFAB6242615302C77DC16D2185316D392044AC4D88589BD0960222" + $"A4B02A81FDCEF0D116BE84E7EA8530945B0ECFD58B911616D2312C3B1808F0A1" + $"FD9DAFBFB2D90DE2F2965D4F9DC8725E6D997ED4B072C0CC7F077C6AE27DC79B" + $"9AC19AD6221017A676573CC1539CFB4CFA1DAF5CD598CD38A0EF39DDAFBBA550" + $"9D5A00E2DCD22555763C85B686E2C8996BED178B6903828DBCEAEC94A67C2F9C" + $"64610DBF7669B5038FD3E9CF3B3C4B6EEAACDDE4FDF3D4FCE5F4D8EC063F96AE" + $"D6451512B2CFFC1823FB70FAD3B8EAD401FE72BAD8620A08A70CF8F80DD5BB4D" + $"179053E6C2DDFBD608CAB5E601A761181C63483F210EA02530807CCB09760C8E" + $"776018E025549324C8A5790049D04F88CF6B7C4EB12383DF28FE3A552D8D6CE9" + $"B7DC4D0F3FC0F20EB404D1EF1B44627BC866F5A328112D41D48A919541138540" + $"23A9A73D047633E03CCA5C7F00288AC08FE23A7EB30000000049454E44AE4260" + $"82" +}; + +resource(4, "movedown.png") #'PNG ' array { + $"89504E470D0A1A0A0000000D4948445200000018000000180806000000E0773D" + $"F8000001E6494441544889ED92DD4B53611CC73F6ED5BC680D978F6B792AC45C" + $"E164577A9710E7A6B0BAEAAE0B41F09F08BAEAC66E4421F042AF6A228A2F28BA" + $"A42226859B48DD0C247A811C8E1DE2D0081793A9674F174B523BCF966F78515F" + $"F8C173CEF7F7FB7E785EE0BF8E5B15A5CC90C0DD7543BC3DEB7707ECFC6F46D6" + $"B8FFDC6C4A98645419274A013417D50D37EB030D772ED8FA9FA657FCDA9CD991" + $"80EE7D010028AC83B5A6F6C0556AFC2F0079B0726AAF8CCA03E426588A20B979" + $"08006B437D44D6C6DE0121C169CD8500F07BD09059B04EDA4FCB2C7E0F556D50" + $"0790CA63264C7E6C6FF9E3998EDF6631D8265A1CCEE2F7994BE0BB627F8F5F3F" + $"E4594D16D7050B969E99CB7767080159E50EE2691E5FCD9B4F03B704158E5F3F" + $"1577E0BB5C2C5980F71193789A97401058D8EA71EE1E8A1924BC192A6BDDB96B" + $"D5753990E5EBE38B1C4383841FBD631A7803584A00C0EB34AF6A329CABF5D0EC" + $"BD0848757D9E83E130230F17990422C08EEDDA0200A22922DA771ACF0B82559A" + $"7DCF9705187BC2D48338A3C00CA0786E0A0970F4B6329B0C23E5D2CE4A86913D" + $"ADCC02F700F79E827743FA74A2A991DFE1A96164DF75A202DA01CFBEC3B7419C" + $"033A316302698C23077462023A00EF81C3B7A4C1A97E9DF97E9D790D3A8BDCC3" + $"970368067C4711FE8FEA273678C1FAFB9AC8FD0000000049454E44AE426082" +}; diff --git a/src/apps/resourceedit/ResourceListView.cpp b/src/apps/resourceedit/ResourceListView.cpp new file mode 100644 index 0000000000..654de4420b --- /dev/null +++ b/src/apps/resourceedit/ResourceListView.cpp @@ -0,0 +1,60 @@ +/* + * Copyright 2012-2013 Tri-Edge AI + * All rights reserved. Distributed under the terms of the MIT license. + */ + + +#include "ResourceListView.h" + +#include "Constants.h" + +#include +#include + + +ResourceListView::ResourceListView(BRect rect, const char* name, + uint32 resizingMode, uint32 drawFlags, border_style border, + bool showHorizontalScrollbar) + : + BColumnListView(rect, name, resizingMode, drawFlags, border, + showHorizontalScrollbar) +{ + //SetMouseTrackingEnabled(true); +} + + +ResourceListView::~ResourceListView() +{ + +} + + +void +ResourceListView::MouseDown(BPoint point) +{ + PRINT(("MouseDown()")); +} + + +void +ResourceListView::MessageReceived(BMessage* msg) +{ + switch (msg->what) { + case B_SIMPLE_DATA: + { + entry_ref ref; + int32 n = 0; + + // TODO: Implement D&D adding of files. + + while (msg->FindRef("refs", n++, &ref) == B_OK) { + PRINT(("%s\n", ref.name)); + // ... + } + + break; + } + default: + BColumnListView::MessageReceived(msg); + } +} diff --git a/src/apps/resourceedit/ResourceListView.h b/src/apps/resourceedit/ResourceListView.h new file mode 100644 index 0000000000..88657f9376 --- /dev/null +++ b/src/apps/resourceedit/ResourceListView.h @@ -0,0 +1,27 @@ +/* + * Copyright 2012-2013 Tri-Edge AI + * All rights reserved. Distributed under the terms of the MIT license. + */ +#ifndef RESOURCE_LIST_VIEW_H +#define RESOURCE_LIST_VIEW_H + + +#include + + +class ResourceListView : public BColumnListView { +public: + ResourceListView(BRect rect, const char* name, uint32 resizingMode, + uint32 drawFlags, border_style border = B_NO_BORDER, + bool showHorizontalScrollbar = true); + ~ResourceListView(); + + void MouseDown(BPoint point); + void MessageReceived(BMessage* msg); + +private: + +}; + + +#endif diff --git a/src/apps/resourceedit/ResourceRow.cpp b/src/apps/resourceedit/ResourceRow.cpp new file mode 100644 index 0000000000..ecf94f709c --- /dev/null +++ b/src/apps/resourceedit/ResourceRow.cpp @@ -0,0 +1,153 @@ +/* + * Copyright 2012-2013 Tri-Edge AI + * All rights reserved. Distributed under the terms of the MIT license. + */ + + +#include "ResourceRow.h" + +#include +#include + +#include + + +ResourceRow::ResourceRow() + : + BRow() +{ + Parent = NULL; + ActionIndex = -1; + + SetField(new BStringField(""), 0); + SetField(new BStringField(""), 1); + SetField(new BStringField(""), 2); + SetField(new BStringField(""), 3); + SetField(new BStringField(""), 4); + SetField(new BSizeField(0), 5); +} + + +ResourceRow::~ResourceRow() +{ + // ... +} + + +void +ResourceRow::SetResourceID(int32 id) +{ + ((BStringField*)GetField(0))->SetString((BString() << id).String()); +} + + +void +ResourceRow::SetResourceStringID(const char* id) +{ + ((BStringField*)GetField(0))->SetString(id); +} + + +void +ResourceRow::SetResourceName(const char* name) +{ + ((BStringField*)GetField(1))->SetString(name); +} + + +void +ResourceRow::SetResourceType(const char* type) +{ + ((BStringField*)GetField(2))->SetString(type); +} + + +void +ResourceRow::SetResourceCode(type_code code) +{ + fCode = code; + ResourceType::CodeToString(code, fTypeString); + ((BStringField*)GetField(3))->SetString(fTypeString); +} + + +void +ResourceRow::SetResourceStringCode(const char* code) +{ + fCode = ResourceType::StringToCode(code); + ((BStringField*)GetField(3))->SetString(code); +} + + +void +ResourceRow::SetResourceData(const char* data) +{ + ((BStringField*)GetField(4))->SetString(data); +} + + +void +ResourceRow::SetResourceSize(off_t size) +{ + ((BSizeField*)GetField(5))->SetSize(size); +} + + +int32 +ResourceRow::ResourceID() +{ + const char* strID = ResourceStringID(); + + // TODO: Check whether is numeric and resolve if not. + + return atoi(strID); +} + + +const char* +ResourceRow::ResourceStringID() +{ + return ((BStringField*)GetField(0))->String(); +} + + +const char* +ResourceRow::ResourceName() +{ + return ((BStringField*)GetField(1))->String(); +} + + +const char* +ResourceRow::ResourceType() +{ + return ((BStringField*)GetField(2))->String(); +} + + +type_code +ResourceRow::ResourceCode() +{ + return fCode; +} + + +const char* +ResourceRow::ResourceStringCode() +{ + return ((BStringField*)GetField(3))->String(); +} + + +const char* +ResourceRow::ResourceData() +{ + return ((BStringField*)GetField(4))->String(); +} + + +off_t +ResourceRow::ResourceSize() +{ + return ((BSizeField*)GetField(5))->Size(); +} diff --git a/src/apps/resourceedit/ResourceRow.h b/src/apps/resourceedit/ResourceRow.h new file mode 100644 index 0000000000..26d3660ff9 --- /dev/null +++ b/src/apps/resourceedit/ResourceRow.h @@ -0,0 +1,46 @@ +/* + * Copyright 2012-2013 Tri-Edge AI + * All rights reserved. Distributed under the terms of the MIT license. + */ +#ifndef RESOURCE_ROW_H +#define RESOURCE_ROW_H + + +#include "DefaultTypes.h" + +#include + + +class ResourceRow : public BRow { +public: + ResourceRow(); + ~ResourceRow(); + + void SetResourceID(int32 id); + void SetResourceStringID(const char* id); + void SetResourceName(const char* name); + void SetResourceType(const char* type); + void SetResourceCode(type_code code); + void SetResourceStringCode(const char* code); + void SetResourceData(const char* data); + void SetResourceSize(off_t size); + + int32 ResourceID(); + const char* ResourceStringID(); + const char* ResourceName(); + const char* ResourceType(); + type_code ResourceCode(); + const char* ResourceStringCode(); + const char* ResourceData(); + off_t ResourceSize(); + + ResourceRow* Parent; + int32 ActionIndex; +private: + type_code fCode; + char fTypeString[8]; + +}; + + +#endif diff --git a/src/apps/resourceedit/SettingsFile.cpp b/src/apps/resourceedit/SettingsFile.cpp new file mode 100644 index 0000000000..63e84b5d9d --- /dev/null +++ b/src/apps/resourceedit/SettingsFile.cpp @@ -0,0 +1,56 @@ +/* + * Copyright 2012-2013 Tri-Edge AI + * All rights reserved. Distributed under the terms of the MIT license. + */ + + +#include "SettingsFile.h" + + +SettingsFile::SettingsFile(const char* name) +{ + find_directory(B_USER_SETTINGS_DIRECTORY, &fPath); + fPath.Append(name, true); +} + + +SettingsFile::~SettingsFile() +{ + +} + + +void +SettingsFile::Defaults() +{ + UndoLimit = 100; +} + + +void +SettingsFile::Load() +{ + fFile = new BFile(fPath.Path(), B_READ_ONLY); + + if (fFile->InitCheck() == B_OK) { + fFile->Read(&UndoLimit, sizeof(UndoLimit)); + // TODO: Add more settings here (2/3). + } else + Defaults(); + + delete fFile; +} + + +void +SettingsFile::Save() +{ + fFile = new BFile(fPath.Path(), B_WRITE_ONLY | B_CREATE_FILE); + + if (fFile->InitCheck() == B_OK) { + fFile->Write(&UndoLimit, sizeof(UndoLimit)); + // TODO: Add more settings here (3/3). + } + + delete fFile; +} diff --git a/src/apps/resourceedit/SettingsFile.h b/src/apps/resourceedit/SettingsFile.h new file mode 100644 index 0000000000..2c52232b4b --- /dev/null +++ b/src/apps/resourceedit/SettingsFile.h @@ -0,0 +1,33 @@ +/* + * Copyright 2012-2013 Tri-Edge AI + * All rights reserved. Distributed under the terms of the MIT license. + */ +#ifndef SETTINGS_FILE_H +#define SETTINGS_FILE_H + + +#include +#include +#include + + +class SettingsFile +{ +public: + int32 UndoLimit; + // TODO: Add more settings here (1/3). + + SettingsFile(const char* name); + ~SettingsFile(); + + void Defaults(); + void Load(); + void Save(); + +private: + BPath fPath; + BFile* fFile; +}; + + +#endif diff --git a/src/apps/resourceedit/SettingsWindow.cpp b/src/apps/resourceedit/SettingsWindow.cpp new file mode 100644 index 0000000000..9817659cb9 --- /dev/null +++ b/src/apps/resourceedit/SettingsWindow.cpp @@ -0,0 +1,120 @@ +/* + * Copyright 2012-2013 Tri-Edge AI + * All rights reserved. Distributed under the terms of the MIT license. + */ + + +#include "SettingsWindow.h" + +#include "Constants.h" +#include "GenericSettingsView.h" +#include "SettingsFile.h" + +#include +#include +#include +#include +#include +#include +#include + + +SettingsWindow::SettingsWindow(SettingsFile* settings) + : + BWindow(BRect(200, 150, 600, 450), "Settings", B_TITLED_WINDOW, B_NOT_RESIZABLE) +{ + fSettings = settings; + + BRect bounds = Bounds(); + + fBackView = new BView(bounds, "fBackView", B_FOLLOW_ALL, 0); + fBackView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + + fListView = new BListView(BRect(8, 8, 100 + 8, bounds.bottom - 8), + "fListView", B_SINGLE_SELECTION_LIST, B_FOLLOW_ALL); + + // TODO: Implement selecting different categories of settings. + // fListView->SetSelectionMessage(new BMessage(...)); + + fListView->AddItem(new BStringItem("Generic")); + fListView->Select(0); + + fScrollView = new BScrollView("fScrollView", fListView, B_FOLLOW_TOP_BOTTOM, + B_WILL_DRAW | B_FRAME_EVENTS, false, true); + + fGenericSettingsView = new GenericSettingsView( + BRect(132, 8, bounds.right - 8, bounds.bottom - 8 - 40), + "fGenericSettingsView", fSettings); + // TODO: Add more settings views (2/4). + + fRevertButton = new BButton(BRect(bounds.right - 152, bounds.bottom - 32, + bounds.right - 88, bounds.bottom - 8), + "fRevertButton", "Revert", + new BMessage(MSG_SETTINGS_REVERT)); + + fApplyButton = new BButton(BRect(bounds.right - 72, bounds.bottom - 32, + bounds.right - 8, bounds.bottom - 8), "fApplyButton", "Apply", + new BMessage(MSG_SETTINGS_APPLY)); + + AdaptSettings(); + + fBackView->AddChild(fScrollView); + fBackView->AddChild(fGenericSettingsView); + fBackView->AddChild(fRevertButton); + fBackView->AddChild(fApplyButton); + AddChild(fBackView); + + Show(); +} + + +SettingsWindow::~SettingsWindow() +{ + +} + + +bool +SettingsWindow::QuitRequested() +{ + be_app->PostMessage(MSG_SETTINGS_CLOSED); + return true; +} + +void +SettingsWindow::MessageReceived(BMessage* msg) +{ + switch (msg->what) + { + case MSG_SETTINGS_APPLY: + { + ApplySettings(); + fSettings->Save(); + be_app->PostMessage(MSG_SETTINGS_APPLY); + break; + } + case MSG_SETTINGS_REVERT: + { + AdaptSettings(); + fSettings->Save(); + be_app->PostMessage(MSG_SETTINGS_APPLY); + break; + } + default: + BWindow::MessageReceived(msg); + } +} + +void +SettingsWindow::ApplySettings() +{ + fGenericSettingsView->ApplySettings(); + // TODO: Add more settings views (3/4). +} + +void +SettingsWindow::AdaptSettings() +{ + fGenericSettingsView->AdaptSettings(); + // TODO: Add more settings views (4/4). +} diff --git a/src/apps/resourceedit/SettingsWindow.h b/src/apps/resourceedit/SettingsWindow.h new file mode 100644 index 0000000000..da015de5bf --- /dev/null +++ b/src/apps/resourceedit/SettingsWindow.h @@ -0,0 +1,48 @@ +/* + * Copyright 2012-2013 Tri-Edge AI + * All rights reserved. Distributed under the terms of the MIT license. + */ +#ifndef SETTINGS_WINDOW_H +#define SETTINGS_WINDOW_H + + +#include + + +class GenericSettingsView; +class SettingsFile; + +class BButton; +class BListView; +class BScrollView; +class BView; + + +class SettingsWindow : public BWindow { +public: + SettingsWindow(SettingsFile* settings); + ~SettingsWindow(); + + bool QuitRequested(); + void MessageReceived(BMessage* msg); + + void ApplySettings(); + void AdaptSettings(); + +private: + SettingsFile* fSettings; + + BView* fBackView; + BListView* fListView; + BScrollView* fScrollView; + + GenericSettingsView* fGenericSettingsView; + // TODO: Add more settings (1/4). + + BButton* fRevertButton; + BButton* fApplyButton; + +}; + + +#endif diff --git a/src/apps/resourceedit/edits/AppFlagsEdit.cpp b/src/apps/resourceedit/edits/AppFlagsEdit.cpp new file mode 100644 index 0000000000..5a1482533a --- /dev/null +++ b/src/apps/resourceedit/edits/AppFlagsEdit.cpp @@ -0,0 +1,4 @@ +/* + * Copyright 2012-2013 Tri-Edge AI + * All rights reserved. Distributed under the terms of the MIT license. + */ diff --git a/src/apps/resourceedit/edits/AppFlagsEdit.h b/src/apps/resourceedit/edits/AppFlagsEdit.h new file mode 100644 index 0000000000..5a1482533a --- /dev/null +++ b/src/apps/resourceedit/edits/AppFlagsEdit.h @@ -0,0 +1,4 @@ +/* + * Copyright 2012-2013 Tri-Edge AI + * All rights reserved. Distributed under the terms of the MIT license. + */ diff --git a/src/apps/resourceedit/edits/BooleanEdit.cpp b/src/apps/resourceedit/edits/BooleanEdit.cpp new file mode 100644 index 0000000000..bf65a9335e --- /dev/null +++ b/src/apps/resourceedit/edits/BooleanEdit.cpp @@ -0,0 +1,71 @@ +/* + * Copyright 2012-2013 Tri-Edge AI + * All rights reserved. Distributed under the terms of the MIT license. + */ + + +#include "NormalEdit.h" +#include "ResourceRow.h" + +#include +#include +#include + + +BooleanEdit::BooleanEdit() + : + EditView("BooleanEdit") +{ + +} + + +BooleanEdit::~BooleanEdit() +{ + +} + + +void +BooleanEdit::AttachTo(BView* view) +{ + EditView::AttachTo(view); + + SetLayout(new BGroupLayout(B_VERTICAL)); + + fValueCheck = new BCheckBox(BRect(0, 0, 0, 0), "fValueText", + "", NULL); + + AddChild(BGroupLayoutBuilder(B_VERTICAL, 0) + .Add(fValueCheck) + .AddGlue() + ); + + view->AddChild(this); +} + + +void +BooleanEdit::Edit(ResourceRow* row) +{ + EditView::Edit(row); + + BString data = fRow->ResourceData(); + + if (data == "" || data == "0" || data == "false") + fValueCheck->SetValue(B_CONTROL_OFF); + else + fValueCheck->SetValue(B_CONTROL_ON); +} + + +void +BooleanEdit::Commit() +{ + EditView::Commit(); + + if (fValueCheck->Value() == B_CONTROL_ON) + fRow->SetResourceData("true"); + else + fRow->SetResourceData("false"); +} diff --git a/src/apps/resourceedit/edits/BooleanEdit.h b/src/apps/resourceedit/edits/BooleanEdit.h new file mode 100644 index 0000000000..53889992bb --- /dev/null +++ b/src/apps/resourceedit/edits/BooleanEdit.h @@ -0,0 +1,30 @@ +/* + * Copyright 2012-2013 Tri-Edge AI + * All rights reserved. Distributed under the terms of the MIT license. + */ +#ifndef BOOLEAN_EDIT_H +#define BOOLEAN_EDIT_H + + +#include "EditView.h" + + +class BCheckBox; + + +class BooleanEdit : public EditView { +public: + BooleanEdit(); + ~BooleanEdit(); + + void AttachTo(BView* view); + void Edit(ResourceRow* row); + void Commit(); + +private: + BCheckBox* fValueCheck; + +}; + + +#endif diff --git a/src/apps/resourceedit/edits/EditView.cpp b/src/apps/resourceedit/edits/EditView.cpp new file mode 100644 index 0000000000..dc9861aeb4 --- /dev/null +++ b/src/apps/resourceedit/edits/EditView.cpp @@ -0,0 +1,52 @@ +/* + * Copyright 2012-2013 Tri-Edge AI + * All rights reserved. Distributed under the terms of the MIT license. + */ + + +#include "EditView.h" + + +EditView::EditView(const char* name) + : + BView(BRect(0, 0, 0, 0), name, 0, 0) +{ + // Implemented by subclasses. +} + + +EditView::~EditView() +{ + // Implemented by subclasses. +} + + +void +EditView::AttachTo(BView* view) +{ + while (true) { + BView* child = ChildAt(0); + + if (child == NULL) + break; + + child->RemoveSelf(); + } + + // Implemented by subclasses. +} + + +void +EditView::Edit(ResourceRow* row) +{ + fRow = row; + // Implemented by subclasses. +} + + +void +EditView::Commit() +{ + // Implemented by subclasses. +} diff --git a/src/apps/resourceedit/edits/EditView.h b/src/apps/resourceedit/edits/EditView.h new file mode 100644 index 0000000000..23aca74036 --- /dev/null +++ b/src/apps/resourceedit/edits/EditView.h @@ -0,0 +1,31 @@ +/* + * Copyright 2012-2013 Tri-Edge AI + * All rights reserved. Distributed under the terms of the MIT license. + */ +#ifndef EDIT_VIEW_H +#define EDIT_VIEW_H + + +#include + + +class ResourceRow; + + +class EditView : public BView { +public: + EditView(const char* name); + virtual ~EditView(); + + virtual void AttachTo(BView* view); + virtual void Edit(ResourceRow* row); + virtual void Commit(); + +protected: + ResourceRow* fRow; + +}; + + +#endif + diff --git a/src/apps/resourceedit/edits/NormalEdit.cpp b/src/apps/resourceedit/edits/NormalEdit.cpp new file mode 100644 index 0000000000..fa822515bf --- /dev/null +++ b/src/apps/resourceedit/edits/NormalEdit.cpp @@ -0,0 +1,64 @@ +/* + * Copyright 2012-2013 Tri-Edge AI + * All rights reserved. Distributed under the terms of the MIT license. + */ + + +#include "NormalEdit.h" +#include "ResourceRow.h" + +#include +#include +#include + + +NormalEdit::NormalEdit() + : + EditView("NormalEdit") +{ + +} + + +NormalEdit::~NormalEdit() +{ + +} + + +void +NormalEdit::AttachTo(BView* view) +{ + EditView::AttachTo(view); + + SetLayout(new BGroupLayout(B_VERTICAL)); + + fValueText = new BTextControl(BRect(0, 0, 0, 0), "fValueText", + "Value:", "", NULL); + fValueText->SetDivider(50); + + AddChild(BGroupLayoutBuilder(B_VERTICAL, 0) + .Add(fValueText) + .AddGlue() + ); + + view->AddChild(this); +} + + +void +NormalEdit::Edit(ResourceRow* row) +{ + EditView::Edit(row); + + fValueText->SetText(fRow->ResourceData()); +} + + +void +NormalEdit::Commit() +{ + EditView::Commit(); + + fRow->SetResourceData(fValueText->Text()); +} diff --git a/src/apps/resourceedit/edits/NormalEdit.h b/src/apps/resourceedit/edits/NormalEdit.h new file mode 100644 index 0000000000..ea5fe78e09 --- /dev/null +++ b/src/apps/resourceedit/edits/NormalEdit.h @@ -0,0 +1,31 @@ +/* + * Copyright 2012-2013 Tri-Edge AI + * All rights reserved. Distributed under the terms of the MIT license. + */ +#ifndef NORMAL_EDIT_H +#define NORMAL_EDIT_H + + +#include "EditView.h" + + +class BTextControl; + +// TODO: Templatize this class and rename to NumericEdit. +//template +class NormalEdit : public EditView { +public: + NormalEdit(); + ~NormalEdit(); + + void AttachTo(BView* view); + void Edit(ResourceRow* row); + void Commit(); + +private: + BTextControl* fValueText; + +}; + + +#endif diff --git a/src/apps/resourceedit/interface/ImageButton.cpp b/src/apps/resourceedit/interface/ImageButton.cpp new file mode 100644 index 0000000000..7b0b8dd995 --- /dev/null +++ b/src/apps/resourceedit/interface/ImageButton.cpp @@ -0,0 +1,67 @@ +/* + * Copyright 2012-2013 Tri-Edge AI + * All rights reserved. Distributed under the terms of the MIT license. + */ + + +#include "ImageButton.h" + +#include + + +ImageButton::ImageButton(BRect frame, const char* name, BBitmap* image, + BMessage* message, uint32 resizingMode = B_FOLLOW_NONE) + : + BButton(frame, name, "", message, resizingMode) +{ + fImage = image; + + fDrawPoint.x = ((frame.RightTop().x - frame.LeftTop().x) + - (image->Bounds().RightBottom().x + 1)) / 2; + + fDrawPoint.y = ((frame.LeftBottom().y - frame.LeftTop().y) + - (image->Bounds().RightBottom().y + 1)) / 2; + + fInnerBounds = Bounds(); + fInnerBounds.InsetBy(3, 3); + + SetDrawingMode(B_OP_ALPHA); +} + + +ImageButton::~ImageButton() +{ + +} + + +void +ImageButton::Draw(BRect updateRect) +{ + BButton::Draw(updateRect); + DrawBitmap(fImage, fDrawPoint); + + if (!IsEnabled()) { + rgb_color tempColor = HighColor(); + SetHighColor(255, 255, 255, 155); + FillRect(fInnerBounds, B_SOLID_HIGH); + SetHighColor(tempColor); + } +} + + +void +ImageButton::ResizeTo(float width, float height) +{ + BButton::ResizeTo(width, height); + fInnerBounds = Bounds(); + fInnerBounds.InsetBy(3, 3); +} + + +void +ImageButton::SetBitmap(BBitmap* image) +{ + fImage = image; + Invalidate(); +} diff --git a/src/apps/resourceedit/interface/ImageButton.h b/src/apps/resourceedit/interface/ImageButton.h new file mode 100644 index 0000000000..e0c3de8c89 --- /dev/null +++ b/src/apps/resourceedit/interface/ImageButton.h @@ -0,0 +1,32 @@ +/* + * Copyright 2012-2013 Tri-Edge AI + * All rights reserved. Distributed under the terms of the MIT license. + */ +#ifndef IMAGE_BUTTON_H +#define IMAGE_BUTTON_H + + +#include + + +class ImageButton : public BButton +{ +public: + ImageButton(BRect frame, const char* name, BBitmap* image, + BMessage* message, uint32 resizingMode); + ~ImageButton(); + + void Draw(BRect updateRect); + void ResizeTo(float width, float height); + + void SetBitmap(BBitmap* image); + +private: + BBitmap* fImage; + BPoint fDrawPoint; + BRect fInnerBounds; + +}; + + +#endif diff --git a/src/apps/resourceedit/main.cpp b/src/apps/resourceedit/main.cpp new file mode 100644 index 0000000000..b370361660 --- /dev/null +++ b/src/apps/resourceedit/main.cpp @@ -0,0 +1,17 @@ +/* + * Copyright 2012-2013 Tri-Edge AI + * All rights reserved. Distributed under the terms of the MIT license. + */ + + +#include "ResourceEdit.h" + + +int +main() +{ + ResourceEdit* app = new ResourceEdit(); + app->Run(); + delete app; + return 0; +} diff --git a/src/apps/resourceedit/settings/GenericSettingsView.cpp b/src/apps/resourceedit/settings/GenericSettingsView.cpp new file mode 100644 index 0000000000..65d3377b6c --- /dev/null +++ b/src/apps/resourceedit/settings/GenericSettingsView.cpp @@ -0,0 +1,60 @@ +/* + * Copyright 2012-2013 Tri-Edge AI + * All rights reserved. Distributed under the terms of the MIT license. + */ + + +#include "GenericSettingsView.h" + +#include "SettingsFile.h" + +#include +#include +#include +#include + +#include + + +GenericSettingsView::GenericSettingsView(BRect frame, const char* name, + SettingsFile* settings, uint32 resizingMode, uint32 flags) + : + BView(frame, name, resizingMode, flags) +{ + fSettings = settings; + + SetLayout(new BGroupLayout(B_VERTICAL)); + + fUndoLimitText = new BTextControl(BRect(0, 0, 0, 0), "fUndoLimitText", + "Undo Limit:", NULL, NULL); + fUndoLimitText->SetDivider(100); + + // TODO: Add more controls for generic settings (2/4). + + AddChild(BGroupLayoutBuilder(B_VERTICAL, 8) + .Add(fUndoLimitText) + .AddGlue() + ); +} + + +GenericSettingsView::~GenericSettingsView() +{ + +} + + +void +GenericSettingsView::ApplySettings() +{ + fSettings->UndoLimit = atoi(fUndoLimitText->Text()); + // TODO: Add more controls for generic settings (3/4). +} + + +void +GenericSettingsView::AdaptSettings() +{ + fUndoLimitText->SetText(BString() << fSettings->UndoLimit); + // TODO: Add more controls for generic settings (4/4). +} diff --git a/src/apps/resourceedit/settings/GenericSettingsView.h b/src/apps/resourceedit/settings/GenericSettingsView.h new file mode 100644 index 0000000000..47d141127a --- /dev/null +++ b/src/apps/resourceedit/settings/GenericSettingsView.h @@ -0,0 +1,37 @@ +/* + * Copyright 2012-2013 Tri-Edge AI + * All rights reserved. Distributed under the terms of the MIT license. + */ +#ifndef GENERIC_SETTINGS_VIEW_H +#define GENERIC_SETTINGS_VIEW_H + + +#include + + +class SettingsFile; + +class BTextControl; + + +class GenericSettingsView : public BView { +public: + GenericSettingsView(BRect frame, const char* name, + SettingsFile* settings, + uint32 resizingMode = B_FOLLOW_ALL, + uint32 flags = 0); + ~GenericSettingsView(); + + void ApplySettings(); + void AdaptSettings(); + +private: + SettingsFile* fSettings; + + BTextControl* fUndoLimitText; + // TODO: Add more controls for generic settings (1/4). + +}; + + +#endif diff --git a/src/apps/resourceedit/support/UndoContext.cpp b/src/apps/resourceedit/support/UndoContext.cpp new file mode 100644 index 0000000000..c4f6775b2d --- /dev/null +++ b/src/apps/resourceedit/support/UndoContext.cpp @@ -0,0 +1,175 @@ +/* + * Copyright 2012-2013 Tri-Edge AI + * All rights reserved. Distributed under the terms of the MIT license. + */ + + +#include "UndoContext.h" + +#include "Constants.h" + +#include +#include + + +UndoContext::Action::Action(const BString& label) +{ + fLabel = label; +} + + +UndoContext::Action::~Action() +{ + +} + + +void +UndoContext::Action::Do() +{ + +} + + +void +UndoContext::Action::Undo() +{ + +} + + +void +UndoContext::Action::SetLabel(const BString& label) +{ + fLabel = label; +} + + +BString +UndoContext::Action::Label() const +{ + return fLabel; +} + + +UndoContext::UndoContext() +{ + fAt = 0; + fLimit = 3; + fHistory = new BList(); +} + + +UndoContext::~UndoContext() +{ + for (int32 i = 0; i < fHistory->CountItems(); i++) + delete (Action*)fHistory->ItemAt(i); + + delete fHistory; +} + + +void +UndoContext::SetLimit(int32 limit) +{ + int32 delta = fLimit - limit; + + if (limit > 1) + fLimit = limit; + else + limit = 1; + + if (delta > 0) { + for (int32 i = 0; i < delta; i++) + delete (Action*)fHistory->ItemAt(i); + + fHistory->RemoveItems(0, delta); + + if (fAt > fLimit) + fAt = fLimit; + } +} + + +int32 +UndoContext::Limit() const +{ + return fLimit; +} + + +void +UndoContext::Do(UndoContext::Action* action) +{ + int32 count = fHistory->CountItems(); + + if (fAt >= fLimit) + delete (Action*)fHistory->RemoveItem((int32)0); + else { + for (int32 i = fAt; i < count; i++) + delete (Action*)fHistory->ItemAt(i); + + fHistory->RemoveItems(fAt, count - fAt); + + fAt++; + } + + fHistory->AddItem(action); + + action->Do(); +} + + +void +UndoContext::Undo() +{ + if (!CanUndo()) + return; + + fAt--; + ((Action*)fHistory->ItemAt(fAt))->Undo(); +} + + +void +UndoContext::Redo() +{ + if (!CanRedo()) + return; + + ((Action*)fHistory->ItemAt(fAt))->Do(); + fAt++; +} + + +bool +UndoContext::CanUndo() const +{ + return fAt > 0; +} + + +bool +UndoContext::CanRedo() const +{ + return fAt < fHistory->CountItems(); +} + + +BString +UndoContext::UndoLabel() const +{ + if (CanUndo()) + return ((Action*)fHistory->ItemAt(fAt - 1))->Label(); + else + return ""; +} + +BString +UndoContext::RedoLabel() const +{ + if (CanRedo()) + return ((Action*)fHistory->ItemAt(fAt))->Label(); + else + return ""; +} diff --git a/src/apps/resourceedit/support/UndoContext.h b/src/apps/resourceedit/support/UndoContext.h new file mode 100644 index 0000000000..0146e1be48 --- /dev/null +++ b/src/apps/resourceedit/support/UndoContext.h @@ -0,0 +1,55 @@ +/* + * Copyright 2012-2013 Tri-Edge AI + * All rights reserved. Distributed under the terms of the MIT license. + */ +#ifndef UNDO_CONTEXT_H +#define UNDO_CONTEXT_H + + +#include +#include + + +class UndoContext { +public: + class Action { + public: + Action(const BString& label); + virtual ~Action(); + + virtual void Do(); + virtual void Undo(); + + void SetLabel(const BString& label); + BString Label() const; + + private: + BString fLabel; + }; + + UndoContext(); + ~UndoContext(); + + void SetLimit(int32 limit); + int32 Limit() const; + + void Do(Action* action); + + void Undo(); + void Redo(); + + bool CanUndo() const; + bool CanRedo() const; + + BString UndoLabel() const; + BString RedoLabel() const; + +private: + int32 fAt; + int32 fLimit; + BList* fHistory; + +}; + + +#endif diff --git a/src/apps/showimage/Jamfile b/src/apps/showimage/Jamfile index 87aa25bced..3ff8552b08 100644 --- a/src/apps/showimage/Jamfile +++ b/src/apps/showimage/Jamfile @@ -17,7 +17,6 @@ Application ShowImage : ShowImageApp.cpp ShowImageSettings.cpp ShowImageStatusView.cpp - ShowImageUndo.cpp ShowImageView.cpp ShowImageWindow.cpp ToolBarIcons.cpp diff --git a/src/apps/showimage/ShowImageUndo.cpp b/src/apps/showimage/ShowImageUndo.cpp deleted file mode 100644 index d4c2ad7cf8..0000000000 --- a/src/apps/showimage/ShowImageUndo.cpp +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright 2003-2009 Haiku Inc. All rights reserved. - * Distributed under the terms of the MIT License. - * - * Authors: - * Michael Wilber - */ - -#include "ShowImageUndo.h" - -#include -#include - - -ShowImageUndo::ShowImageUndo() - : - fWindow(NULL), - fUndoType(0), - fRestore(NULL), - fSelection(NULL) -{ -} - - -ShowImageUndo::~ShowImageUndo() -{ - InternalClear(); -} - - -void -ShowImageUndo::InternalClear() -{ - fUndoType = 0; - delete fRestore; - fRestore = NULL; - delete fSelection; - fSelection = NULL; -} - - -void -ShowImageUndo::Clear() -{ - InternalClear(); - SendUndoStateMessage(false); -} - - -void -ShowImageUndo::SendUndoStateMessage(bool bCanUndo) -{ - if (fWindow) { - if (!fWindow->IsLocked()) { - fprintf(stderr, - "ShowImageUndo::SendUndoStateMessage: window must be locked!"); - exit(-1); - } - BMessage msg(MSG_UNDO_STATE); - msg.AddBool("can_undo", bCanUndo); - fWindow->PostMessage(&msg); - } -} - - -void -ShowImageUndo::SetTo(BRect rect, BBitmap* restore, BBitmap* selection) -{ - // NOTE: THIS FUNCTION DOES NOT MAKE COPIES OF THE BITMAPS PASSED TO IT - InternalClear(); - - fUndoType = UNDO_UNDO; - fRect = rect; - fRestore = restore; - fSelection = selection; - - SendUndoStateMessage(true); -} - - -void -ShowImageUndo::Undo(BRect rect, BBitmap* restore, BBitmap* selection) -{ - // NOTE: THIS FUNCTION DOES NOT MAKE COPIES OF THE BITMAPS PASSED TO IT - fUndoType = UNDO_REDO; - fRect = rect; - delete fRestore; - fRestore = restore; - fSelection = selection; - // NOTE: fSelection isn't deleted here because ShowImageView - // takes ownership of it during an Undo -} - diff --git a/src/apps/showimage/ShowImageUndo.h b/src/apps/showimage/ShowImageUndo.h deleted file mode 100644 index 7cfc8d8159..0000000000 --- a/src/apps/showimage/ShowImageUndo.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2003-2009 Haiku Inc. All rights reserved. - * Distributed under the terms of the MIT License. - * - * Authors: - * Michael Wilber - */ -#ifndef SHOW_IMAGE_UNDO_H -#define SHOW_IMAGE_UNDO_H - - -#include -#include -#include -#include -#include - -#include "ShowImageConstants.h" - - -// for Undo -#define UNDO_UNDO 1 -#define UNDO_REDO 2 - - -class ShowImageUndo { -public: - ShowImageUndo(); - ~ShowImageUndo(); - - void SetWindow(BWindow* win) { fWindow = win; } - - void Clear(); - - // NOTE: THESE TWO FUNCTIONS DO NOT MAKE COPIES OF THE - // BITMAPS PASSED TO THEM - void SetTo(BRect rect, BBitmap* restore, BBitmap* selection); - void Undo(BRect rect, BBitmap* restore, BBitmap* selection); - - int32 GetType() { return fUndoType; } - BRect GetRect() { return fRect; } - BBitmap* GetRestoreBitmap() { return fRestore; } - BBitmap* GetSelectionBitmap() { return fSelection; } - -private: - void InternalClear(); - void SendUndoStateMessage(bool bCanUndo); - - BWindow* fWindow; - // Window to which notification messages are sent - int32 fUndoType; - // Nothing, Undo or Redo - BRect fRect; - // Area of background bitmap where change took place - BBitmap* fRestore; - // Changed portion of background bitmap, before change took place - BBitmap* fSelection; - // Selection present before change took place -}; - - -#endif // SHOW_IMAGE_UNDO_H - diff --git a/src/apps/showimage/ShowImageView.cpp b/src/apps/showimage/ShowImageView.cpp index 3f8899575f..3a39f8872b 100644 --- a/src/apps/showimage/ShowImageView.cpp +++ b/src/apps/showimage/ShowImageView.cpp @@ -244,13 +244,16 @@ ShowImageView::Pulse() } if (fHideCursor && !fHasSelection && !fShowingPopUpMenu && fIsActiveWin) { - if (fHideCursorCountDown <= 0) { + if (fHideCursorCountDown == 0) { + // Go negative so this isn't triggered again + fHideCursorCountDown--; + BPoint mousePos; uint32 buttons; GetMouse(&mousePos, &buttons, false); if (Bounds().Contains(mousePos)) be_app->ObscureCursor(); - } else + } else if (fHideCursorCountDown > 0) fHideCursorCountDown--; } @@ -365,7 +368,6 @@ ShowImageView::SetImage(const entry_ref* ref, BBitmap* bitmap, BitmapOwner* bitmapOwner) { // Delete the old one, and clear everything - fUndo.Clear(); _SetHasSelection(false); fCreatingSelection = false; _DeleteBitmap(); @@ -531,7 +533,6 @@ void ShowImageView::AttachedToWindow() { FitToBounds(); - fUndo.SetWindow(Window()); FixupScrollBars(); } @@ -1476,47 +1477,6 @@ ShowImageView::SetSelectionMode(bool selectionMode) } -void -ShowImageView::Undo() -{ - int32 undoType = fUndo.GetType(); - if (undoType != UNDO_UNDO && undoType != UNDO_REDO) - return; - - // backup current selection - BRect undoneSelRect; - BBitmap* undoneSelection; - undoneSelRect = fSelectionBox.Bounds(); - undoneSelection = _CopySelection(); - - if (undoType == UNDO_UNDO) { - BBitmap* undoRestore; - undoRestore = fUndo.GetRestoreBitmap(); - if (undoRestore) - _MergeWithBitmap(undoRestore, fUndo.GetRect()); - } - - // restore previous image/selection - BBitmap* undoSelection; - undoSelection = fUndo.GetSelectionBitmap(); - // NOTE: ShowImageView is responsible for deleting this bitmap - // (Which it will, as it would with a fSelectionBitmap that it - // allocated itself) - if (!undoSelection) - _SetHasSelection(false); - else { - fCopyFromRect = BRect(); - fSelectionBox.SetBounds(this, fUndo.GetRect()); - _SetHasSelection(true); - fSelectionBitmap = undoSelection; - } - - fUndo.Undo(undoneSelRect, NULL, undoneSelection); - - Invalidate(); -} - - void ShowImageView::SelectAll() { @@ -1729,7 +1689,6 @@ ShowImageView::_DoImageOperation(ImageProcessor::operation op, bool quiet) void ShowImageView::_UserDoImageOperation(ImageProcessor::operation op, bool quiet) { - fUndo.Clear(); _DoImageOperation(op, quiet); } @@ -1770,7 +1729,6 @@ ShowImageView::ResizeImage(int w, int h) // remove selection _SetHasSelection(false); - fUndo.Clear(); _DeleteBitmap(); fBitmap = scaled; diff --git a/src/apps/showimage/ShowImageView.h b/src/apps/showimage/ShowImageView.h index bdf4d106f6..33f312770e 100644 --- a/src/apps/showimage/ShowImageView.h +++ b/src/apps/showimage/ShowImageView.h @@ -24,7 +24,6 @@ #include "Filter.h" #include "SelectionBox.h" -#include "ShowImageUndo.h" class BitmapOwner; @@ -82,7 +81,6 @@ public: void SetSelectionMode(bool selectionMode); bool IsSelectionModeEnabled() const { return fSelectionMode; } - void Undo(); void SelectAll(); void ClearSelection(); @@ -182,7 +180,6 @@ private: void _ShowToolBarIfEnabled(bool show); private: - ShowImageUndo fUndo; entry_ref fCurrentRef; BitmapOwner* fBitmapOwner; diff --git a/src/apps/showimage/ShowImageWindow.cpp b/src/apps/showimage/ShowImageWindow.cpp index 8464ed20d7..fbd6a54663 100644 --- a/src/apps/showimage/ShowImageWindow.cpp +++ b/src/apps/showimage/ShowImageWindow.cpp @@ -418,8 +418,6 @@ ShowImageWindow::_AddMenus(BMenuBar* bar) bar->AddItem(menu); menu = new BMenu(B_TRANSLATE("Edit")); - _AddItemMenu(menu, B_TRANSLATE("Undo"), B_UNDO, 'Z', 0, this, false); - menu->AddSeparatorItem(); _AddItemMenu(menu, B_TRANSLATE("Copy"), B_COPY, 'C', 0, this, false); menu->AddSeparatorItem(); _AddItemMenu(menu, B_TRANSLATE("Selection mode"), MSG_SELECTION_MODE, 0, 0, @@ -767,18 +765,6 @@ ShowImageWindow::MessageReceived(BMessage* message) break; } - case MSG_UNDO_STATE: - { - bool enable; - if (message->FindBool("can_undo", &enable) == B_OK) - _EnableMenuItem(fBar, B_UNDO, enable); - break; - } - - case B_UNDO: - fImageView->Undo(); - break; - case B_COPY: fImageView->CopySelectionToClipboard(); break; diff --git a/src/bin/Jamfile b/src/bin/Jamfile index 4d1f6530bb..a06268af96 100644 --- a/src/bin/Jamfile +++ b/src/bin/Jamfile @@ -253,6 +253,7 @@ SubInclude HAIKU_TOP src bin hid_decode ; SubInclude HAIKU_TOP src bin iasl ; SubInclude HAIKU_TOP src bin ideinfo ; SubInclude HAIKU_TOP src bin keymap ; +SubInclude HAIKU_TOP src bin keystore ; SubInclude HAIKU_TOP src bin less ; SubInclude HAIKU_TOP src bin listdev ; SubInclude HAIKU_TOP src bin locale ; diff --git a/src/bin/keystore/Jamfile b/src/bin/keystore/Jamfile new file mode 100644 index 0000000000..8577d772a1 --- /dev/null +++ b/src/bin/keystore/Jamfile @@ -0,0 +1,6 @@ +SubDir HAIKU_TOP src bin keystore ; + +BinCommand keystore : + keystore.cpp + : be + : keystore.rdef ; diff --git a/src/bin/keystore/keystore.cpp b/src/bin/keystore/keystore.cpp new file mode 100644 index 0000000000..682db34f14 --- /dev/null +++ b/src/bin/keystore/keystore.cpp @@ -0,0 +1,459 @@ +/* + * Copyright 2012, Haiku Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Michael Lotz, mmlr@mlotz.ch + */ + + +#include +#include + +#include + + +int +add_password(const char* keyring, const char* identifier, + const char* secondaryIdentifier, const char* passwordString) +{ + BKeyStore keyStore; + BPasswordKey password(passwordString, B_KEY_PURPOSE_GENERIC, identifier, + secondaryIdentifier); + + status_t result = keyStore.AddKey(keyring, password); + if (result != B_OK) { + printf("failed to add password: %s\n", strerror(result)); + return 2; + } + + return 0; +} + + +int +remove_password(const char* keyring, const char* identifier, + const char* secondaryIdentifier) +{ + BKeyStore keyStore; + BPasswordKey password; + + status_t result = keyStore.GetKey(keyring, B_KEY_TYPE_PASSWORD, identifier, + secondaryIdentifier, false, password); + if (result != B_OK) { + printf("failed to get password \"%s\": %s\n", identifier, + strerror(result)); + return 2; + } + + result = keyStore.RemoveKey(keyring, password); + if (result != B_OK) { + printf("failed to remove password: %s\n", strerror(result)); + return 3; + } + + return 0; +} + + +int +add_keyring(const char* keyring) +{ + BKeyStore keyStore; + + status_t result = keyStore.AddKeyring(keyring); + if (result != B_OK) { + printf("failed to add keyring: %s\n", strerror(result)); + return 2; + } + + return 0; +} + + +int +remove_keyring(const char* keyring) +{ + BKeyStore keyStore; + + status_t result = keyStore.RemoveKeyring(keyring); + if (result != B_OK) { + printf("failed to remove keyring: %s\n", strerror(result)); + return 2; + } + + return 0; +} + + +int +list_passwords(const char* keyring) +{ + BKeyStore keyStore; + uint32 cookie = 0; + + while (true) { + BPasswordKey password; + status_t result = keyStore.GetNextKey(keyring, B_KEY_TYPE_PASSWORD, + B_KEY_PURPOSE_ANY, cookie, password); + if (result == B_ENTRY_NOT_FOUND) + break; + + if (result != B_OK) { + printf("failed to get next key with: %s\n", strerror(result)); + return 2; + } + + password.PrintToStream(); + } + + return 0; +} + + +int +list_keyrings() +{ + BKeyStore keyStore; + uint32 cookie = 0; + + while (true) { + BString keyring; + status_t result = keyStore.GetNextKeyring(cookie, keyring); + if (result == B_ENTRY_NOT_FOUND) + break; + + if (result != B_OK) { + printf("failed to get next key with: %s\n", strerror(result)); + return 2; + } + + printf("keyring: \"%s\"\n", keyring.String()); + } + + return 0; +} + + +int +show_status(const char* keyring) +{ + BKeyStore keyStore; + printf("keyring \"%s\" is %slocked\n", keyring, + keyStore.IsKeyringUnlocked(keyring) ? "un" : ""); + return 0; +} + + +int +lock_keyring(const char* keyring) +{ + BKeyStore keyStore; + status_t result = keyStore.LockKeyring(keyring); + if (result != B_OK) { + printf("failed to lock keyring \"%s\": %s\n", keyring, + strerror(result)); + return 2; + } + + return 0; +} + + +int +add_keyring_to_master(const char* keyring) +{ + BKeyStore keyStore; + status_t result= keyStore.AddKeyringToMaster(keyring); + if (result != B_OK) { + printf("failed to add keyring \"%s\" to master: %s\n", keyring, + strerror(result)); + return 2; + } + + return 0; +} + + +int +remove_keyring_from_master(const char* keyring) +{ + BKeyStore keyStore; + status_t result= keyStore.RemoveKeyringFromMaster(keyring); + if (result != B_OK) { + printf("failed to remove keyring \"%s\" from master: %s\n", keyring, + strerror(result)); + return 2; + } + + return 0; +} + + +int +list_applications(const char* keyring) +{ + BKeyStore keyStore; + uint32 cookie = 0; + + while (true) { + BString signature; + status_t result = keyStore.GetNextApplication(keyring, + cookie, signature); + if (result == B_ENTRY_NOT_FOUND) + break; + + if (result != B_OK) { + printf("failed to get next application: %s\n", strerror(result)); + return 2; + } + + printf("application: \"%s\"\n", signature.String()); + } + + return 0; +} + + +int +remove_application(const char* keyring, const char* signature) +{ + BKeyStore keyStore; + + status_t result = keyStore.RemoveApplication(keyring, signature); + if (result != B_OK) { + printf("failed to remove application: %s\n", strerror(result)); + return 3; + } + + return 0; +} + + +int +set_unlock_key(const char* keyring, const char* passwordString) +{ + BKeyStore keyStore; + BPasswordKey password(passwordString, B_KEY_PURPOSE_KEYRING, NULL); + + status_t result = keyStore.SetUnlockKey(keyring, password); + if (result != B_OK) { + printf("failed to set unlock key: %s\n", strerror(result)); + return 3; + } + + return 0; +} + + +int +remove_unlock_key(const char* keyring) +{ + BKeyStore keyStore; + + status_t result = keyStore.RemoveUnlockKey(keyring); + if (result != B_OK) { + printf("failed to remove unlock key: %s\n", strerror(result)); + return 3; + } + + return 0; +} + + +int +print_usage(const char* name) +{ + printf("usage:\n"); + printf("\t%s list passwords []\n", name); + printf("\t\tLists all passwords of the specified keyring or from the" + " master keyring if none is supplied.\n"); + printf("\t%s list keyrings\n", name); + printf("\t\tLists all keyrings.\n"); + printf("\t%s list applications []\n", name); + printf("\t\tLists the applications that have been granted permanent access" + " to a keyring once it is unlocked.\n\n"); + + printf("\t%s add password [] " + "\n", name); + printf("\t\tAdds the specified password to the master keyring.\n"); + printf("\t%s add password to []" + " \n", name); + printf("\t\tAdds the specified password to the specified keyring.\n\n"); + + printf("\t%s remove password []\n", name); + printf("\t\tRemoves the specified password from the master keyring.\n"); + printf("\t%s remove password from " + " []\n", name); + printf("\t\tRemoves the specified password from the specified keyring.\n\n"); + + printf("\t%s add keyring \n", name); + printf("\t\tAdds a new keyring with the specified name.\n"); + printf("\t%s remove keyring \n", name); + printf("\t\tRemoves the specified keyring.\n\n"); + + printf("\t%s status []\n", name); + printf("\t\tShows the lock state of the specified keyring, or the" + " master keyring if none is supplied.\n\n"); + + printf("\t%s lock []\n", name); + printf("\t\tLock the specified keyring, or the master keyring if none is" + " supplied.\n\n"); + + printf("\t%s master add \n", name); + printf("\t\tAdd the access key for the specified keyring to the master" + " keyring.\n"); + + printf("\t%s master remove \n", name); + printf("\t\tRemove the access key for the specified keyring from the" + " master keyring.\n\n"); + + printf("\t%s remove application \n", name); + printf("\t\tRemove permanent access for the application with the given" + " signature from the master keyring.\n"); + printf("\t%s remove application from \n", name); + printf("\t\tRemove permanent access for the application with the given" + " signature from the specified keyring.\n\n"); + + printf("\t%s key set \n", name); + printf("\t\tSet the unlock key of the specified keyring to the given" + " password.\n"); + printf("\t%s key remove \n", name); + printf("\t\tRemove the unlock key of the specified keyring.\n"); + return 1; +} + + +int +main(int argc, char* argv[]) +{ + BApplication app("application/x-vnd.Haiku-keystore-cli"); + + if (argc < 2) + return print_usage(argv[0]); + + if (strcmp(argv[1], "list") == 0) { + if (argc < 3) + return print_usage(argv[0]); + + if (strcmp(argv[2], "passwords") == 0) + return list_passwords(argc > 3 ? argv[3] : NULL); + if (strcmp(argv[2], "keyrings") == 0) + return list_keyrings(); + if (strcmp(argv[2], "applications") == 0) + return list_applications(argc > 3 ? argv[3] : NULL); + } else if (strcmp(argv[1], "add") == 0) { + if (argc < 3) + return print_usage(argv[0]); + + if (strcmp(argv[2], "password") == 0) { + if (argc < 5) + return print_usage(argv[0]); + + const char* keyring = NULL; + const char* identifier = NULL; + const char* secondaryIdentifier = NULL; + const char* password = NULL; + if (argc >= 7 && argc <= 8 && strcmp(argv[3], "to") == 0) { + keyring = argv[4]; + identifier = argv[5]; + if (argc == 7) + password = argv[6]; + else { + secondaryIdentifier = argv[6]; + password = argv[7]; + } + } else if (argc <= 6) { + identifier = argv[3]; + if (argc == 5) + password = argv[4]; + else { + secondaryIdentifier = argv[4]; + password = argv[5]; + } + } + + if (password != NULL) { + return add_password(keyring, identifier, secondaryIdentifier, + password); + } + } else if (strcmp(argv[2], "keyring") == 0) { + if (argc < 4) + return print_usage(argv[0]); + + return add_keyring(argv[3]); + } + } else if (strcmp(argv[1], "remove") == 0) { + if (argc < 3) + return print_usage(argv[0]); + + if (strcmp(argv[2], "password") == 0) { + if (argc < 4) + return print_usage(argv[0]); + + const char* keyring = NULL; + const char* identifier = NULL; + const char* secondaryIdentifier = NULL; + if (argc >= 6 && argc <= 7 && strcmp(argv[3], "from") == 0) { + keyring = argv[4]; + identifier = argv[5]; + if (argc == 7) + secondaryIdentifier = argv[6]; + } else if (argc <= 5) { + identifier = argv[3]; + if (argc == 5) + secondaryIdentifier = argv[4]; + } + + if (identifier != NULL) { + return remove_password(keyring, identifier, + secondaryIdentifier); + } + } else if (strcmp(argv[2], "keyring") == 0) { + if (argc == 4) + return remove_keyring(argv[3]); + } else if (strcmp(argv[2], "application") == 0) { + const char* keyring = NULL; + const char* signature = NULL; + if (argc == 6 && strcmp(argv[3], "from") == 0) { + keyring = argv[4]; + signature = argv[5]; + } else if (argc == 4) + signature = argv[3]; + + if (signature != NULL) + return remove_application(keyring, signature); + } + } else if (strcmp(argv[1], "status") == 0) { + if (argc != 2 && argc != 3) + return print_usage(argv[0]); + + return show_status(argc == 3 ? argv[2] : ""); + } else if (strcmp(argv[1], "lock") == 0) { + if (argc != 2 && argc != 3) + return print_usage(argv[0]); + + return lock_keyring(argc == 3 ? argv[2] : ""); + } else if (strcmp(argv[1], "master") == 0) { + if (argc != 4) + return print_usage(argv[0]); + + if (strcmp(argv[2], "add") == 0) + return add_keyring_to_master(argv[3]); + if (strcmp(argv[2], "remove") == 0) + return remove_keyring_from_master(argv[3]); + } else if (strcmp(argv[1], "key") == 0) { + if (argc < 4) + return print_usage(argv[0]); + + if (strcmp(argv[2], "set") == 0) { + if (argc == 5) + return set_unlock_key(argv[3], argv[4]); + } else if (strcmp(argv[2], "remove") == 0) { + if (argc == 4) + return remove_unlock_key(argv[3]); + } + } + + return print_usage(argv[0]); +} diff --git a/src/bin/keystore/keystore.rdef b/src/bin/keystore/keystore.rdef new file mode 100644 index 0000000000..e98269230a --- /dev/null +++ b/src/bin/keystore/keystore.rdef @@ -0,0 +1,2 @@ +resource app_signature "application/x-vnd.Haiku-keystore-cli"; +resource app_flags B_MULTIPLE_LAUNCH; diff --git a/src/kits/app/Jamfile b/src/kits/app/Jamfile index 1aec0536d7..85e267bd9e 100644 --- a/src/kits/app/Jamfile +++ b/src/kits/app/Jamfile @@ -57,5 +57,9 @@ MergeObject app_kit.o : ServerMemoryAllocator.cpp TokenSpace.cpp TypeConstants.cpp + + # KeyStore implementation + Key.cpp + KeyStore.cpp ; diff --git a/src/kits/app/Key.cpp b/src/kits/app/Key.cpp new file mode 100644 index 0000000000..ffe5374c30 --- /dev/null +++ b/src/kits/app/Key.cpp @@ -0,0 +1,342 @@ +/* + * Copyright 2011, Axel Dörfler, axeld@pinc-software.de. + * Distributed under the terms of the MIT License. + */ + + +#include + +#include + + +#if 0 +// TODO: move this to the KeyStore or the registrar backend if needed +static bool +CompareLists(BObjectList a, BObjectList b) +{ + if (a.CountItems() != b.CountItems()) + return false; + + for (int32 i = 0; i < a.CountItems(); i++) { + if (*a.ItemAt(i) != *b.ItemAt(i)) + return false; + } + + return true; +} +#endif + + +// #pragma mark - Generic BKey + + +BKey::BKey() +{ + Unset(); +} + + +BKey::BKey(BKeyPurpose purpose, const char* identifier, + const char* secondaryIdentifier, const uint8* data, size_t length) +{ + SetTo(purpose, identifier, secondaryIdentifier, data, length); +} + + +BKey::BKey(BKey& other) +{ + *this = other; +} + + +BKey::~BKey() +{ +} + + +void +BKey::Unset() +{ + SetTo(B_KEY_PURPOSE_GENERIC, "", "", NULL, 0); +} + + +status_t +BKey::SetTo(BKeyPurpose purpose, const char* identifier, + const char* secondaryIdentifier, const uint8* data, size_t length) +{ + fCreationTime = 0; + SetPurpose(purpose); + SetIdentifier(identifier); + SetSecondaryIdentifier(secondaryIdentifier); + return SetData(data, length); +} + + +void +BKey::SetPurpose(BKeyPurpose purpose) +{ + fPurpose = purpose; +} + + +BKeyPurpose +BKey::Purpose() const +{ + return fPurpose; +} + + +void +BKey::SetIdentifier(const char* identifier) +{ + fIdentifier = identifier; +} + + +const char* +BKey::Identifier() const +{ + return fIdentifier.String(); +} + + +void +BKey::SetSecondaryIdentifier(const char* identifier) +{ + fSecondaryIdentifier = identifier; +} + + +const char* +BKey::SecondaryIdentifier() const +{ + return fSecondaryIdentifier.String(); +} + + +status_t +BKey::SetData(const uint8* data, size_t length) +{ + fData.SetSize(0); + ssize_t bytesWritten = fData.WriteAt(0, data, length); + if (bytesWritten < 0) + return (status_t)bytesWritten; + + return (size_t)bytesWritten == length ? B_OK : B_NO_MEMORY; +} + + +size_t +BKey::DataLength() const +{ + return fData.BufferLength(); +} + + +const uint8* +BKey::Data() const +{ + return (const uint8*)fData.Buffer(); +} + + +status_t +BKey::GetData(uint8* buffer, size_t bufferSize) const +{ + ssize_t bytesRead = fData.ReadAt(0, buffer, bufferSize); + if (bytesRead < 0) + return (status_t)bytesRead; + + return B_OK; +} + + + +const char* +BKey::Owner() const +{ + return fOwner.String(); +} + + +bigtime_t +BKey::CreationTime() const +{ + return fCreationTime; +} + + +status_t +BKey::Flatten(BMessage& message) const +{ + if (message.MakeEmpty() != B_OK + || message.AddUInt32("type", Type()) != B_OK + || message.AddUInt32("purpose", fPurpose) != B_OK + || message.AddString("identifier", fIdentifier) != B_OK + || message.AddString("secondaryIdentifier", fSecondaryIdentifier) + != B_OK + || message.AddString("owner", fOwner) != B_OK + || message.AddInt64("creationTime", fCreationTime) != B_OK + || message.AddData("data", B_RAW_TYPE, fData.Buffer(), + fData.BufferLength()) != B_OK) { + return B_ERROR; + } + + return B_OK; +} + + +status_t +BKey::Unflatten(const BMessage& message) +{ + BKeyType type; + if (message.FindUInt32("type", (uint32*)&type) != B_OK || type != Type()) + return B_BAD_VALUE; + + const void* data = NULL; + ssize_t dataLength = 0; + if (message.FindUInt32("purpose", (uint32*)&fPurpose) != B_OK + || message.FindString("identifier", &fIdentifier) != B_OK + || message.FindString("secondaryIdentifier", &fSecondaryIdentifier) + != B_OK + || message.FindString("owner", &fOwner) != B_OK + || message.FindInt64("creationTime", &fCreationTime) != B_OK + || message.FindData("data", B_RAW_TYPE, &data, &dataLength) != B_OK + || dataLength < 0) { + return B_ERROR; + } + + return SetData((const uint8*)data, (size_t)dataLength); +} + + +BKey& +BKey::operator=(const BKey& other) +{ + SetPurpose(other.Purpose()); + SetData((const uint8*)other.Data(), other.DataLength()); + + fIdentifier = other.fIdentifier; + fSecondaryIdentifier = other.fSecondaryIdentifier; + fOwner = other.fOwner; + fCreationTime = other.fCreationTime; + + return *this; +} + + +bool +BKey::operator==(const BKey& other) const +{ + return Type() == other.Type() + && DataLength() == other.DataLength() + && Purpose() == other.Purpose() + && fOwner == other.fOwner + && fIdentifier == other.fIdentifier + && fSecondaryIdentifier == other.fSecondaryIdentifier + && memcmp(Data(), other.Data(), DataLength()) == 0; +} + + +bool +BKey::operator!=(const BKey& other) const +{ + return !(*this == other); +} + + +void +BKey::PrintToStream() +{ + if (Type() == B_KEY_TYPE_GENERIC) + printf("generic key:\n"); + + const char* purposeString = "unknown"; + switch (fPurpose) { + case B_KEY_PURPOSE_ANY: + purposeString = "any"; + break; + case B_KEY_PURPOSE_GENERIC: + purposeString = "generic"; + break; + case B_KEY_PURPOSE_KEYRING: + purposeString = "keyring"; + break; + case B_KEY_PURPOSE_WEB: + purposeString = "web"; + break; + case B_KEY_PURPOSE_NETWORK: + purposeString = "network"; + break; + case B_KEY_PURPOSE_VOLUME: + purposeString = "volume"; + break; + } + + printf("\tpurpose: %s\n", purposeString); + printf("\tidentifier: \"%s\"\n", fIdentifier.String()); + printf("\tsecondary identifier: \"%s\"\n", fSecondaryIdentifier.String()); + printf("\towner: \"%s\"\n", fOwner.String()); + printf("\tcreation time: %" B_PRIu64 "\n", fCreationTime); + printf("\traw data length: %" B_PRIuSIZE "\n", fData.BufferLength()); +} + + +// #pragma mark - BPasswordKey + + +BPasswordKey::BPasswordKey() +{ +} + + +BPasswordKey::BPasswordKey(const char* password, BKeyPurpose purpose, + const char* identifier, const char* secondaryIdentifier) + : + BKey(purpose, identifier, secondaryIdentifier, (const uint8*)password, + strlen(password) + 1) +{ +} + + +BPasswordKey::BPasswordKey(BPasswordKey& other) +{ +} + + +BPasswordKey::~BPasswordKey() +{ +} + + +status_t +BPasswordKey::SetTo(const char* password, BKeyPurpose purpose, + const char* identifier, const char* secondaryIdentifier) +{ + return BKey::SetTo(purpose, identifier, secondaryIdentifier, + (const uint8*)password, strlen(password) + 1); +} + + +status_t +BPasswordKey::SetPassword(const char* password) +{ + return SetData((const uint8*)password, strlen(password) + 1); +} + + +const char* +BPasswordKey::Password() const +{ + return (const char*)Data(); +} + + +void +BPasswordKey::PrintToStream() +{ + printf("password key:\n"); + BKey::PrintToStream(); + printf("\tpassword: \"%s\"\n", Password()); +} diff --git a/src/kits/app/KeyStore.cpp b/src/kits/app/KeyStore.cpp new file mode 100644 index 0000000000..c72b87a7a5 --- /dev/null +++ b/src/kits/app/KeyStore.cpp @@ -0,0 +1,434 @@ +/* + * Copyright 2011, Axel Dörfler, axeld@pinc-software.de. + * Distributed under the terms of the MIT License. + */ + + +#include + +#include + +#include + + +using namespace BPrivate; + + +BKeyStore::BKeyStore() +{ +} + + +BKeyStore::~BKeyStore() +{ +} + + +// #pragma mark - Key handling + + +status_t +BKeyStore::GetKey(BKeyType type, const char* identifier, BKey& key) +{ + return GetKey(NULL, type, identifier, NULL, true, key); +} + + +status_t +BKeyStore::GetKey(BKeyType type, const char* identifier, + const char* secondaryIdentifier, BKey& key) +{ + return GetKey(NULL, type, identifier, secondaryIdentifier, true, key); +} + + +status_t +BKeyStore::GetKey(BKeyType type, const char* identifier, + const char* secondaryIdentifier, bool secondaryIdentifierOptional, + BKey& key) +{ + return GetKey(NULL, type, identifier, secondaryIdentifier, + secondaryIdentifierOptional, key); +} + + +status_t +BKeyStore::GetKey(const char* keyring, BKeyType type, const char* identifier, + BKey& key) +{ + return GetKey(keyring, type, identifier, NULL, true, key); +} + + +status_t +BKeyStore::GetKey(const char* keyring, BKeyType type, const char* identifier, + const char* secondaryIdentifier, BKey& key) +{ + return GetKey(keyring, type, identifier, secondaryIdentifier, true, key); +} + + +status_t +BKeyStore::GetKey(const char* keyring, BKeyType type, const char* identifier, + const char* secondaryIdentifier, bool secondaryIdentifierOptional, + BKey& key) +{ + BMessage message(KEY_STORE_GET_KEY); + message.AddString("keyring", keyring); + message.AddUInt32("type", type); + message.AddString("identifier", identifier); + message.AddString("secondaryIdentifier", secondaryIdentifier); + message.AddBool("secondaryIdentifierOptional", secondaryIdentifierOptional); + + BMessage reply; + status_t result = _SendKeyMessage(message, &reply); + if (result != B_OK) + return result; + + BMessage keyMessage; + if (reply.FindMessage("key", &keyMessage) != B_OK) + return B_ERROR; + + return key.Unflatten(keyMessage); +} + + +status_t +BKeyStore::AddKey(const BKey& key) +{ + return AddKey(NULL, key); +} + + +status_t +BKeyStore::AddKey(const char* keyring, const BKey& key) +{ + BMessage keyMessage; + if (key.Flatten(keyMessage) != B_OK) + return B_BAD_VALUE; + + BMessage message(KEY_STORE_ADD_KEY); + message.AddString("keyring", keyring); + message.AddMessage("key", &keyMessage); + + return _SendKeyMessage(message, NULL); +} + + +status_t +BKeyStore::RemoveKey(const BKey& key) +{ + return RemoveKey(NULL, key); +} + + +status_t +BKeyStore::RemoveKey(const char* keyring, const BKey& key) +{ + BMessage keyMessage; + if (key.Flatten(keyMessage) != B_OK) + return B_BAD_VALUE; + + BMessage message(KEY_STORE_REMOVE_KEY); + message.AddString("keyring", keyring); + message.AddMessage("key", &keyMessage); + + return _SendKeyMessage(message, NULL); +} + + +status_t +BKeyStore::GetNextKey(uint32& cookie, BKey& key) +{ + return GetNextKey(NULL, cookie, key); +} + + +status_t +BKeyStore::GetNextKey(BKeyType type, BKeyPurpose purpose, uint32& cookie, + BKey& key) +{ + return GetNextKey(NULL, type, purpose, cookie, key); +} + + +status_t +BKeyStore::GetNextKey(const char* keyring, uint32& cookie, BKey& key) +{ + return GetNextKey(keyring, B_KEY_TYPE_ANY, B_KEY_PURPOSE_ANY, cookie, key); +} + + +status_t +BKeyStore::GetNextKey(const char* keyring, BKeyType type, BKeyPurpose purpose, + uint32& cookie, BKey& key) +{ + BMessage message(KEY_STORE_GET_NEXT_KEY); + message.AddString("keyring", keyring); + message.AddUInt32("type", type); + message.AddUInt32("purpose", purpose); + message.AddUInt32("cookie", cookie); + + BMessage reply; + status_t result = _SendKeyMessage(message, &reply); + if (result != B_OK) + return result; + + BMessage keyMessage; + if (reply.FindMessage("key", &keyMessage) != B_OK) + return B_ERROR; + + reply.FindUInt32("cookie", &cookie); + return key.Unflatten(keyMessage); +} + + +// #pragma mark - Keyrings + + +status_t +BKeyStore::AddKeyring(const char* keyring) +{ + BMessage message(KEY_STORE_ADD_KEYRING); + message.AddString("keyring", keyring); + return _SendKeyMessage(message, NULL); +} + + +status_t +BKeyStore::RemoveKeyring(const char* keyring) +{ + BMessage message(KEY_STORE_REMOVE_KEYRING); + message.AddString("keyring", keyring); + return _SendKeyMessage(message, NULL); +} + + +status_t +BKeyStore::GetNextKeyring(uint32& cookie, BString& keyring) +{ + BMessage message(KEY_STORE_GET_NEXT_KEYRING); + message.AddUInt32("cookie", cookie); + + BMessage reply; + status_t result = _SendKeyMessage(message, &reply); + if (result != B_OK) + return result; + + if (reply.FindString("keyring", &keyring) != B_OK) + return B_ERROR; + + reply.FindUInt32("cookie", &cookie); + return B_OK; +} + + +status_t +BKeyStore::SetUnlockKey(const char* keyring, const BKey& key) +{ + BMessage keyMessage; + if (key.Flatten(keyMessage) != B_OK) + return B_BAD_VALUE; + + BMessage message(KEY_STORE_SET_UNLOCK_KEY); + message.AddString("keyring", keyring); + message.AddMessage("key", &keyMessage); + + return _SendKeyMessage(message, NULL); +} + + +status_t +BKeyStore::RemoveUnlockKey(const char* keyring) +{ + BMessage message(KEY_STORE_REMOVE_UNLOCK_KEY); + message.AddString("keyring", keyring); + return _SendKeyMessage(message, NULL); +} + + +// #pragma mark - Master key + + +status_t +BKeyStore::SetMasterUnlockKey(const BKey& key) +{ + return SetUnlockKey(NULL, key); +} + + +status_t +BKeyStore::RemoveMasterUnlockKey() +{ + return RemoveUnlockKey(NULL); +} + + +status_t +BKeyStore::AddKeyringToMaster(const char* keyring) +{ + BMessage message(KEY_STORE_ADD_KEYRING_TO_MASTER); + message.AddString("keyring", keyring); + return _SendKeyMessage(message, NULL); +} + + +status_t +BKeyStore::RemoveKeyringFromMaster(const char* keyring) +{ + BMessage message(KEY_STORE_REMOVE_KEYRING_FROM_MASTER); + message.AddString("keyring", keyring); + return _SendKeyMessage(message, NULL); +} + + +status_t +BKeyStore::GetNextMasterKeyring(uint32& cookie, BString& keyring) +{ + BMessage message(KEY_STORE_GET_NEXT_MASTER_KEYRING); + message.AddUInt32("cookie", cookie); + + BMessage reply; + status_t result = _SendKeyMessage(message, &reply); + if (result != B_OK) + return result; + + if (reply.FindString("keyring", &keyring) != B_OK) + return B_ERROR; + + reply.FindUInt32("cookie", &cookie); + return B_OK; +} + + +// #pragma mark - Locking + + +bool +BKeyStore::IsKeyringUnlocked(const char* keyring) +{ + BMessage message(KEY_STORE_IS_KEYRING_UNLOCKED); + message.AddString("keyring", keyring); + + BMessage reply; + if (_SendKeyMessage(message, &reply) != B_OK) + return false; + + bool unlocked; + if (reply.FindBool("unlocked", &unlocked) != B_OK) + return false; + + return unlocked; +} + + +status_t +BKeyStore::LockKeyring(const char* keyring) +{ + BMessage message(KEY_STORE_LOCK_KEYRING); + message.AddString("keyring", keyring); + return _SendKeyMessage(message, NULL); +} + + +status_t +BKeyStore::LockMasterKeyring() +{ + return LockKeyring(NULL); +} + + + +// #pragma mark - Applications + + +status_t +BKeyStore::GetNextApplication(uint32& cookie, BString& signature) const +{ + return GetNextApplication(NULL, cookie, signature); +} + + +status_t +BKeyStore::GetNextApplication(const char* keyring, uint32& cookie, + BString& signature) const +{ + BMessage message(KEY_STORE_GET_NEXT_APPLICATION); + message.AddString("keyring", keyring); + message.AddUInt32("cookie", cookie); + + BMessage reply; + status_t result = _SendKeyMessage(message, &reply); + if (result != B_OK) + return result; + + if (reply.FindString("signature", &signature) != B_OK) + return B_ERROR; + + reply.FindUInt32("cookie", &cookie); + return B_OK; +} + + +status_t +BKeyStore::RemoveApplication(const char* signature) +{ + return RemoveApplication(NULL, signature); +} + + +status_t +BKeyStore::RemoveApplication(const char* keyring, const char* signature) +{ + BMessage message(KEY_STORE_REMOVE_APPLICATION); + message.AddString("keyring", keyring); + message.AddString("signature", signature); + + return _SendKeyMessage(message, NULL); +} + + +// #pragma mark - Service functions + + +status_t +BKeyStore::GeneratePassword(BPasswordKey& password, size_t length, uint32 flags) +{ + return B_ERROR; +} + + +float +BKeyStore::PasswordStrength(const char* password) +{ + return 0; +} + + +// #pragma mark - Private functions + + +status_t +BKeyStore::_SendKeyMessage(BMessage& message, BMessage* reply) const +{ + BMessage localReply; + if (reply == NULL) + reply = &localReply; + + BMessenger messenger(kKeyStoreServerSignature); + if (!messenger.IsValid()) + return B_ERROR; + + if (messenger.SendMessage(&message, reply) != B_OK) + return B_ERROR; + + if (reply->what != KEY_STORE_SUCCESS) { + status_t result = B_ERROR; + if (reply->FindInt32("result", &result) != B_OK) + return B_ERROR; + + return result; + } + + return B_OK; +} diff --git a/src/kits/interface/ColumnListView.cpp b/src/kits/interface/ColumnListView.cpp index 91bf16a430..ec8b1affa7 100644 --- a/src/kits/interface/ColumnListView.cpp +++ b/src/kits/interface/ColumnListView.cpp @@ -523,6 +523,13 @@ BRow::IsExpanded() const } +bool +BRow::IsSelected() const +{ + return fPrevSelected != NULL; +} + + void BRow::ValidateFields() const { @@ -1258,6 +1265,60 @@ BColumnListView::UpdateRow(BRow* row) } +bool +BColumnListView::SwapRows(int32 index1, int32 index2, BRow* parentRow1, + BRow* parentRow2) +{ + BRow* row1 = NULL; + BRow* row2 = NULL; + + BRowContainer* container1 = NULL; + BRowContainer* container2 = NULL; + + if (parentRow1 == NULL) + container1 = fOutlineView->RowList(); + else + container1 = parentRow1->fChildList; + + if (container1 == NULL) + return false; + + if (parentRow2 == NULL) + container2 = fOutlineView->RowList(); + else + container2 = parentRow1->fChildList; + + if (container2 == NULL) + return false; + + row1 = container1->ItemAt(index1); + + if (row1 == NULL) + return false; + + row2 = container2->ItemAt(index2); + + if (row2 == NULL) + return false; + + container1->ReplaceItem(index2, row1); + container2->ReplaceItem(index1, row2); + + BRect rect1; + BRect rect2; + BRect rect; + + fOutlineView->FindRect(row1, &rect1); + fOutlineView->FindRect(row2, &rect2); + + rect = rect1 | rect2; + + fOutlineView->Invalidate(rect); + + return true; +} + + void BColumnListView::ScrollTo(const BRow* row) { @@ -4195,7 +4256,7 @@ OutlineView::AddRow(BRow* row, int32 Index, BRow* parentRow) row->fParent = parentRow; - if (fMasterView->SortingEnabled()) { + if (fMasterView->SortingEnabled() && !fSortColumns->IsEmpty()) { // Ignore index here. if (parentRow) { if (parentRow->fChildList == NULL) diff --git a/src/kits/interface/ControlLook.cpp b/src/kits/interface/ControlLook.cpp index 4b0910e19b..33bbe6231c 100644 --- a/src/kits/interface/ControlLook.cpp +++ b/src/kits/interface/ControlLook.cpp @@ -740,14 +740,14 @@ BControlLook::DrawArrowShape(BView* view, BRect& rect, const BRect& updateRect, case B_LEFT_ARROW: tri1.Set(rect.right, rect.top); tri2.Set(rect.right - rect.Width() / 1.33, - (rect.top + rect.bottom + 1) /2 ); + (rect.top + rect.bottom + 1) / 2); tri3.Set(rect.right, rect.bottom + 1); break; case B_RIGHT_ARROW: - tri1.Set(rect.left, rect.bottom + 1); - tri2.Set(rect.left + rect.Width() / 1.33, + tri1.Set(rect.left + 1, rect.bottom + 1); + tri2.Set(rect.left + 1 + rect.Width() / 1.33, (rect.top + rect.bottom + 1) / 2); - tri3.Set(rect.left, rect.top); + tri3.Set(rect.left + 1, rect.top); break; case B_UP_ARROW: tri1.Set(rect.left, rect.bottom); @@ -757,17 +757,12 @@ BControlLook::DrawArrowShape(BView* view, BRect& rect, const BRect& updateRect, break; case B_DOWN_ARROW: default: - tri1.Set(rect.left, rect.top); + tri1.Set(rect.left, rect.top + 1); tri2.Set((rect.left + rect.right + 1) / 2, - rect.top + rect.Height() / 1.33); - tri3.Set(rect.right + 1, rect.top); + rect.top + 1 + rect.Height() / 1.33); + tri3.Set(rect.right + 1, rect.top + 1); break; } - // offset triangle if down - if ((flags & B_ACTIVATED) != 0) - view->MovePenTo(BPoint(1, 1)); - else - view->MovePenTo(BPoint(0, 0)); BShape arrowShape; arrowShape.MoveTo(tri1); @@ -782,6 +777,8 @@ BControlLook::DrawArrowShape(BView* view, BRect& rect, const BRect& updateRect, float penSize = view->PenSize(); drawing_mode mode = view->DrawingMode(); + view->MovePenTo(BPoint(0, 0)); + view->SetPenSize(ceilf(hInset / 2.0)); view->SetDrawingMode(B_OP_OVER); view->StrokeShape(&arrowShape); diff --git a/src/kits/interface/Menu.cpp b/src/kits/interface/Menu.cpp index 8491d2fcce..0485f9779b 100644 --- a/src/kits/interface/Menu.cpp +++ b/src/kits/interface/Menu.cpp @@ -1107,6 +1107,7 @@ BMenu::FindMarked() { for (int32 i = 0; i < fItems.CountItems(); i++) { BMenuItem* item = ItemAt(i); + if (item->IsMarked()) return item; } @@ -1115,6 +1116,20 @@ BMenu::FindMarked() } +int32 +BMenu::FindMarkedIndex() +{ + for (int32 i = 0; i < fItems.CountItems(); i++) { + BMenuItem* item = ItemAt(i); + + if (item->IsMarked()) + return i; + } + + return -1; +} + + BMenu* BMenu::Supermenu() const { diff --git a/src/kits/interface/MenuBar.cpp b/src/kits/interface/MenuBar.cpp index b29f9d5ef5..b582d87087 100644 --- a/src/kits/interface/MenuBar.cpp +++ b/src/kits/interface/MenuBar.cpp @@ -340,9 +340,9 @@ BMenuBar::MouseDown(BPoint where) uint32 buttons; GetMouse(&where, &buttons); - - BWindow* window = Window(); - if (!window->IsActive() || !window->IsFront()) { + + BWindow* window = Window(); + if (!window->IsActive() || !window->IsFront()) { if ((mouse_mode() == B_FOCUS_FOLLOWS_MOUSE) || ((mouse_mode() == B_CLICK_TO_FOCUS_MOUSE) && ((buttons & B_SECONDARY_MOUSE_BUTTON) != 0))) { @@ -500,8 +500,8 @@ BMenuBar::StartMenuBar(int32 menuIndex, bool sticky, bool showMenu, fMenuSem = create_sem(0, "window close sem"); _set_menu_sem_(window, fMenuSem); - fTrackingPID = spawn_thread(_TrackTask, "menu_tracking", B_DISPLAY_PRIORITY, - NULL); + fTrackingPID = spawn_thread(_TrackTask, "menu_tracking", + B_DISPLAY_PRIORITY, NULL); if (fTrackingPID >= 0) { menubar_data data; data.menuBar = this; @@ -557,24 +557,22 @@ BMenuBar::_Track(int32* action, int32 startIndex, bool showMenu) { // TODO: Cleanup, merge some "if" blocks if possible fChosenItem = NULL; - - BWindow* window = Window(); fState = MENU_STATE_TRACKING; BPoint where; uint32 buttons; - if (window->Lock()) { + if (LockLooper()) { if (startIndex != -1) { be_app->ObscureCursor(); _SelectItem(ItemAt(startIndex), true, false); } GetMouse(&where, &buttons); - window->Unlock(); + UnlockLooper(); } while (fState != MENU_STATE_CLOSED) { bigtime_t snoozeAmount = 40000; - if (Window() == NULL || !window->Lock()) + if (!LockLooper()) break; BMenuItem* menuItem = NULL; @@ -587,7 +585,7 @@ BMenuBar::_Track(int32* action, int32 startIndex, bool showMenu) // call _Track() from the selected sub-menu when the mouse cursor // is over its window BMenu* menu = fSelected->Submenu(); - window->Unlock(); + UnlockLooper(); snoozeAmount = 30000; bool wasSticky = _IsStickyMode(); menu->_SetStickyMode(wasSticky); @@ -602,9 +600,9 @@ BMenuBar::_Track(int32* action, int32 startIndex, bool showMenu) // where to store the current mouse position ? // (Or just use the BView mouse hooks) BPoint newWhere; - if (window->Lock()) { + if (LockLooper()) { GetMouse(&newWhere, &buttons); - window->Unlock(); + UnlockLooper(); } // This code is needed to make menus @@ -619,7 +617,7 @@ BMenuBar::_Track(int32* action, int32 startIndex, bool showMenu) } else fState = MENU_STATE_CLOSED; } - if (!window->Lock()) + if (!LockLooper()) break; } else if (menuItem != NULL) { if (menuItem->Submenu() != NULL && menuItem != fSelected) { @@ -642,7 +640,7 @@ BMenuBar::_Track(int32* action, int32 startIndex, bool showMenu) fState = MENU_STATE_TRACKING; } - window->Unlock(); + UnlockLooper(); if (fState != MENU_STATE_CLOSED) { // If user doesn't move the mouse, loop here, @@ -680,14 +678,14 @@ BMenuBar::_Track(int32* action, int32 startIndex, bool showMenu) } } - if (window->Lock()) { + if (LockLooper()) { if (fSelected != NULL) _SelectItem(NULL); if (fChosenItem != NULL) fChosenItem->Invoke(); _RestoreFocus(); - window->Unlock(); + UnlockLooper(); } if (_IsStickyMode()) @@ -699,7 +697,6 @@ BMenuBar::_Track(int32* action, int32 startIndex, bool showMenu) *action = fState; return fChosenItem; - } diff --git a/src/kits/interface/ScrollBar.cpp b/src/kits/interface/ScrollBar.cpp index 56099fa8ec..1d6fd3988f 100644 --- a/src/kits/interface/ScrollBar.cpp +++ b/src/kits/interface/ScrollBar.cpp @@ -859,21 +859,17 @@ BScrollBar::Draw(BRect updateRect) bool enabled = fPrivateData->fEnabled && fMin < fMax && fProportion < 1.0 && fProportion >= 0.0; - rgb_color light, light1, dark, dark1, dark2, dark4; + rgb_color light, dark, dark1, dark2; if (enabled) { light = tint_color(normal, B_LIGHTEN_MAX_TINT); - light1 = tint_color(normal, B_LIGHTEN_1_TINT); dark = tint_color(normal, B_DARKEN_3_TINT); dark1 = tint_color(normal, B_DARKEN_1_TINT); dark2 = tint_color(normal, B_DARKEN_2_TINT); - dark4 = tint_color(normal, B_DARKEN_4_TINT); } else { light = tint_color(normal, B_LIGHTEN_MAX_TINT); - light1 = normal; dark = tint_color(normal, B_DARKEN_2_TINT); dark1 = tint_color(normal, B_LIGHTEN_2_TINT); dark2 = tint_color(normal, B_LIGHTEN_1_TINT); - dark4 = tint_color(normal, B_DARKEN_3_TINT); } SetDrawingMode(B_OP_OVER); @@ -943,176 +939,37 @@ BScrollBar::Draw(BRect updateRect) // background for thumb area BRect rect(fPrivateData->fThumbFrame); - if (be_control_look == NULL) { - if (fOrientation == B_HORIZONTAL) { - BeginLineArray(8); - - if (rect.left > thumbBG.left) { - AddLine(BPoint(thumbBG.left, thumbBG.bottom), - BPoint(thumbBG.left, thumbBG.top), - rect.left > thumbBG.left + 1 ? dark4 : dark); - } - if (rect.left > thumbBG.left + 1) { - AddLine(BPoint(thumbBG.left + 1, thumbBG.top + 1), - BPoint(thumbBG.left + 1, thumbBG.bottom), dark2); - AddLine(BPoint(thumbBG.left + 1, thumbBG.top), - BPoint(rect.left - 1, thumbBG.top), dark2); - AddLine(BPoint(rect.left - 1, thumbBG.bottom), - BPoint(thumbBG.left + 2, thumbBG.bottom), normal); - } - - if (rect.right < thumbBG.right - 1) { - AddLine(BPoint(rect.right + 2, thumbBG.top + 1), - BPoint(rect.right + 2, thumbBG.bottom), dark2); - AddLine(BPoint(rect.right + 1, thumbBG.top), - BPoint(thumbBG.right, thumbBG.top), dark2); - AddLine(BPoint(thumbBG.right - 1, thumbBG.bottom), - BPoint(rect.right + 3, thumbBG.bottom), normal); - } - if (rect.right < thumbBG.right) { - AddLine(BPoint(thumbBG.right, thumbBG.top), - BPoint(thumbBG.right, thumbBG.bottom), dark); - } - - EndLineArray(); - } else { - BeginLineArray(8); - - if (rect.top > thumbBG.top) { - AddLine(BPoint(thumbBG.left, thumbBG.top), - BPoint(thumbBG.right, thumbBG.top), - rect.top > thumbBG.top + 1 ? dark4 : dark); - } - if (rect.top > thumbBG.top + 1) { - AddLine(BPoint(thumbBG.left + 1, thumbBG.top + 1), - BPoint(thumbBG.right, thumbBG.top + 1), dark2); - AddLine(BPoint(thumbBG.left, rect.top - 1), - BPoint(thumbBG.left, thumbBG.top + 1), dark2); - AddLine(BPoint(thumbBG.right, rect.top - 1), - BPoint(thumbBG.right, thumbBG.top + 2), normal); - } - - if (rect.bottom < thumbBG.bottom - 1) { - AddLine(BPoint(thumbBG.left + 1, rect.bottom + 2), - BPoint(thumbBG.right, rect.bottom + 2), dark2); - AddLine(BPoint(thumbBG.left, rect.bottom + 1), - BPoint(thumbBG.left, thumbBG.bottom - 1), dark2); - AddLine(BPoint(thumbBG.right, rect.bottom + 3), - BPoint(thumbBG.right, thumbBG.bottom - 1), normal); - } - if (rect.bottom < thumbBG.bottom) { - AddLine(BPoint(thumbBG.left, thumbBG.bottom), - BPoint(thumbBG.right, thumbBG.bottom), dark); - } - - EndLineArray(); - } - } SetHighColor(dark1); - if (be_control_look != NULL) { - uint32 flags = 0; - if (!enabled) - flags |= BControlLook::B_DISABLED; + uint32 flags = 0; + if (!enabled) + flags |= BControlLook::B_DISABLED; - // fill background besides the thumb - if (fOrientation == B_HORIZONTAL) { - BRect leftOfThumb(thumbBG.left, thumbBG.top, rect.left - 1, - thumbBG.bottom); - BRect rightOfThumb(rect.right + 1, thumbBG.top, thumbBG.right, - thumbBG.bottom); + // fill background besides the thumb + if (fOrientation == B_HORIZONTAL) { + BRect leftOfThumb(thumbBG.left, thumbBG.top, rect.left - 1, + thumbBG.bottom); + BRect rightOfThumb(rect.right + 1, thumbBG.top, thumbBG.right, + thumbBG.bottom); - be_control_look->DrawScrollBarBackground(this, leftOfThumb, - rightOfThumb, updateRect, normal, flags, fOrientation); - } else { - BRect topOfThumb(thumbBG.left, thumbBG.top, - thumbBG.right, rect.top - 1); + be_control_look->DrawScrollBarBackground(this, leftOfThumb, + rightOfThumb, updateRect, normal, flags, fOrientation); + } else { + BRect topOfThumb(thumbBG.left, thumbBG.top, + thumbBG.right, rect.top - 1); - BRect bottomOfThumb(thumbBG.left, rect.bottom + 1, - thumbBG.right, thumbBG.bottom); + BRect bottomOfThumb(thumbBG.left, rect.bottom + 1, + thumbBG.right, thumbBG.bottom); - be_control_look->DrawScrollBarBackground(this, topOfThumb, - bottomOfThumb, updateRect, normal, flags, fOrientation); - } + be_control_look->DrawScrollBarBackground(this, topOfThumb, + bottomOfThumb, updateRect, normal, flags, fOrientation); } // Draw scroll thumb if (enabled) { - if (be_control_look == NULL) { - // fill and additional dark lines - thumbBG.InsetBy(1.0, 1.0); - if (fOrientation == B_HORIZONTAL) { - BRect leftOfThumb(thumbBG.left + 1, thumbBG.top, rect.left - 1, - thumbBG.bottom); - if (leftOfThumb.IsValid()) - FillRect(leftOfThumb); - - BRect rightOfThumb(rect.right + 3, thumbBG.top, thumbBG.right, - thumbBG.bottom); - if (rightOfThumb.IsValid()) - FillRect(rightOfThumb); - - // dark lines before and after thumb - if (rect.left > thumbBG.left) { - SetHighColor(dark); - StrokeLine(BPoint(rect.left - 1, rect.top), - BPoint(rect.left - 1, rect.bottom)); - } - if (rect.right < thumbBG.right) { - SetHighColor(dark4); - StrokeLine(BPoint(rect.right + 1, rect.top), - BPoint(rect.right + 1, rect.bottom)); - } - } else { - BRect topOfThumb(thumbBG.left, thumbBG.top + 1, - thumbBG.right, rect.top - 1); - if (topOfThumb.IsValid()) - FillRect(topOfThumb); - - BRect bottomOfThumb(thumbBG.left, rect.bottom + 3, - thumbBG.right, thumbBG.bottom); - if (bottomOfThumb.IsValid()) - FillRect(bottomOfThumb); - - // dark lines before and after thumb - if (rect.top > thumbBG.top) { - SetHighColor(dark); - StrokeLine(BPoint(rect.left, rect.top - 1), - BPoint(rect.right, rect.top - 1)); - } - if (rect.bottom < thumbBG.bottom) { - SetHighColor(dark4); - StrokeLine(BPoint(rect.left, rect.bottom + 1), - BPoint(rect.right, rect.bottom + 1)); - } - } - } - // fill the clickable surface of the thumb - if (be_control_look != NULL) { - be_control_look->DrawButtonBackground(this, rect, updateRect, - normal, 0, BControlLook::B_ALL_BORDERS, fOrientation); - } else { - BeginLineArray(4); - AddLine(BPoint(rect.left, rect.bottom), - BPoint(rect.left, rect.top), light); - AddLine(BPoint(rect.left + 1, rect.top), - BPoint(rect.right, rect.top), light); - AddLine(BPoint(rect.right, rect.top + 1), - BPoint(rect.right, rect.bottom), dark1); - AddLine(BPoint(rect.right - 1, rect.bottom), - BPoint(rect.left + 1, rect.bottom), dark1); - EndLineArray(); - - // fill - rect.InsetBy(1.0, 1.0); - /*if (fPrivateData->fButtonDown == THUMB) - SetHighColor(tint_color(normal, (B_NO_TINT + B_DARKEN_1_TINT) / 2)); - else*/ - SetHighColor(normal); - - FillRect(rect); - } + be_control_look->DrawButtonBackground(this, rect, updateRect, + normal, 0, BControlLook::B_ALL_BORDERS, fOrientation); // TODO: Add the other thumb styles - dots and lines } else { if (fMin >= fMax || fProportion >= 1.0 || fProportion < 0.0) { @@ -1749,152 +1606,31 @@ BScrollBar::_DrawDisabledBackground(BRect area, void -BScrollBar::_DrawArrowButton(int32 direction, bool doubleArrows, BRect r, +BScrollBar::_DrawArrowButton(int32 direction, bool doubleArrows, BRect rect, const BRect& updateRect, bool enabled, bool down) { - if (!updateRect.Intersects(r)) + if (!updateRect.Intersects(rect)) return; - rgb_color c = ui_color(B_PANEL_BACKGROUND_COLOR); - rgb_color light, dark, darker, normal, arrow; + uint32 flags = 0; + if (!enabled) + flags |= BControlLook::B_DISABLED; + if (down && fPrivateData->fDoRepeat) + flags |= BControlLook::B_ACTIVATED; - if (down && fPrivateData->fDoRepeat) { - light = tint_color(c, (B_DARKEN_1_TINT + B_DARKEN_2_TINT) / 2.0); - dark = darker = c; - normal = tint_color(c, B_DARKEN_1_TINT); - arrow = tint_color(c, B_DARKEN_MAX_TINT); + // TODO: Why does BControlLook need this as the base color for the + // scrollbar to look right? + rgb_color baseColor = tint_color(ui_color(B_PANEL_BACKGROUND_COLOR), + B_LIGHTEN_1_TINT); - } else { - // Add a usability perk - disable buttons if they would not do anything - // - like a left arrow if the value == fMin -// NOTE: disabled because of too much visual noise/distraction -/* if ((direction == ARROW_LEFT || direction == ARROW_UP) - && (fValue == fMin)) { - use_enabled_colors = false; - } else if ((direction == ARROW_RIGHT || direction == ARROW_DOWN) - && (fValue == fMax)) { - use_enabled_colors = false; - }*/ + be_control_look->DrawButtonBackground(this, rect, updateRect, baseColor, + flags, BControlLook::B_ALL_BORDERS, fOrientation); - if (enabled) { - light = tint_color(c, B_LIGHTEN_MAX_TINT); - dark = tint_color(c, B_DARKEN_1_TINT); - darker = tint_color(c, B_DARKEN_2_TINT); - normal = c; - arrow = tint_color(c, (B_DARKEN_MAX_TINT + B_DARKEN_4_TINT) / 2.0); - } else { - light = tint_color(c, B_LIGHTEN_MAX_TINT); - dark = tint_color(c, B_LIGHTEN_1_TINT); - darker = tint_color(c, B_DARKEN_2_TINT); - normal = tint_color(c, B_LIGHTEN_2_TINT); - arrow = tint_color(c, B_DARKEN_1_TINT); - } - } - - BPoint tri1, tri2, tri3; - float hInset = r.Width() / 3; - float vInset = r.Height() / 3; - r.InsetBy(hInset, vInset); - - switch (direction) { - case ARROW_LEFT: - tri1.Set(r.right, r.top); - tri2.Set(r.right - r.Width() / 1.33, (r.top + r.bottom + 1) /2 ); - tri3.Set(r.right, r.bottom + 1); - break; - case ARROW_RIGHT: - tri1.Set(r.left, r.bottom + 1); - tri2.Set(r.left + r.Width() / 1.33, (r.top + r.bottom + 1) / 2); - tri3.Set(r.left, r.top); - break; - case ARROW_UP: - tri1.Set(r.left, r.bottom); - tri2.Set((r.left + r.right + 1) / 2, r.bottom - r.Height() / 1.33); - tri3.Set(r.right + 1, r.bottom); - break; - default: - tri1.Set(r.left, r.top); - tri2.Set((r.left + r.right + 1) / 2, r.top + r.Height() / 1.33); - tri3.Set(r.right + 1, r.top); - break; - } - // offset triangle if down - if (down && fPrivateData->fDoRepeat) { - BPoint offset(1.0, 1.0); - tri1 = tri1 + offset; - tri2 = tri2 + offset; - tri3 = tri3 + offset; - } - - r.InsetBy(-(hInset - 1), -(vInset - 1)); - if (be_control_look != NULL) { - BRect temp(r.InsetByCopy(-1, -1)); - uint32 flags = 0; - if (down) - flags |= BControlLook::B_ACTIVATED; - be_control_look->DrawButtonBackground(this, temp, updateRect, - down ? c : normal, flags, BControlLook::B_ALL_BORDERS, - fOrientation); - } else { - SetHighColor(normal); - FillRect(r); - } - - BShape arrowShape; - arrowShape.MoveTo(tri1); - arrowShape.LineTo(tri2); - arrowShape.LineTo(tri3); - - SetHighColor(arrow); - SetPenSize(ceilf(hInset / 2.0)); - StrokeShape(&arrowShape); - SetPenSize(1.0); - - if (be_control_look != NULL) - return; - - r.InsetBy(-1, -1); - BeginLineArray(4); - if (direction == ARROW_LEFT || direction == ARROW_RIGHT) { - // horizontal - if (doubleArrows && direction == ARROW_LEFT) { - // draw in such a way that the arrows are - // more visually separated - AddLine(BPoint(r.left + 1, r.top), - BPoint(r.right - 1, r.top), light); - AddLine(BPoint(r.right, r.top), - BPoint(r.right, r.bottom), darker); - } else { - AddLine(BPoint(r.left + 1, r.top), - BPoint(r.right, r.top), light); - AddLine(BPoint(r.right, r.top + 1), - BPoint(r.right, r.bottom), dark); - } - AddLine(BPoint(r.left, r.bottom), - BPoint(r.left, r.top), light); - AddLine(BPoint(r.right - 1, r.bottom), - BPoint(r.left + 1, r.bottom), dark); - } else { - // vertical - if (doubleArrows && direction == ARROW_UP) { - // draw in such a way that the arrows are - // more visually separated - AddLine(BPoint(r.left, r.bottom - 1), - BPoint(r.left, r.top), light); - AddLine(BPoint(r.right, r.bottom), - BPoint(r.left, r.bottom), darker); - } else { - AddLine(BPoint(r.left, r.bottom), - BPoint(r.left, r.top), light); - AddLine(BPoint(r.right, r.bottom), - BPoint(r.left + 1, r.bottom), dark); - } - AddLine(BPoint(r.left + 1, r.top), - BPoint(r.right, r.top), light); - AddLine(BPoint(r.right, r.top + 1), - BPoint(r.right, r.bottom - 1), dark); - } - EndLineArray(); + // TODO: Why does BControlLook need this negative inset for the arrow to + // look right? + rect.InsetBy(-1, -1); + be_control_look->DrawArrowShape(this, rect, updateRect, + baseColor, direction, flags, B_DARKEN_MAX_TINT); } diff --git a/src/kits/storage/VolumeRoster.cpp b/src/kits/storage/VolumeRoster.cpp index a04bdcd952..3149ab523f 100644 --- a/src/kits/storage/VolumeRoster.cpp +++ b/src/kits/storage/VolumeRoster.cpp @@ -6,10 +6,7 @@ // // Description: BVolumeRoster class // ---------------------------------------------------------------------- -/*! - \file VolumeRoster.cpp - BVolumeRoster implementation. -*/ + #include #include @@ -21,71 +18,32 @@ #include #include + static const char kBootVolumePath[] = "/boot"; using namespace std; + #ifdef USE_OPENBEOS_NAMESPACE namespace OpenBeOS { #endif -/*! - \class BVolumeRoster - \brief A roster of all volumes available in the system - - Provides an interface for iterating through the volumes available in - the system and watching volume mounting/unmounting. - The class wraps the next_dev() function for iterating through the - volume list and the watch_node()/stop_watching() for the watching - features. - - \author Vincent Dominguez - \author Ingo Weinhold - - \version 0.0.0 -*/ - -/*! \var dev_t BVolumeRoster::fCookie - \brief The iteration cookie for next_dev(). Initialized with 0. -*/ - -/*! \var dev_t BVolumeRoster::fTarget - \brief BMessenger referring to the target to which the watching - notification messages are sent. - - The object is allocated and owned by the roster. \c NULL, if not watching. -*/ - -// constructor -/*! \brief Creates a new BVolumeRoster. - - The object is ready to be used. -*/ BVolumeRoster::BVolumeRoster() : fCookie(0), fTarget(NULL) { } -// destructor -/*! \brief Frees all resources associated with this object. - If a watching was activated on (StartWatching()), it is deactived. -*/ +// Deletes the volume roster and frees all associated resources. BVolumeRoster::~BVolumeRoster() { StopWatching(); } -// GetNextVolume -/*! \brief Returns the next volume in the list of available volumes. - \param volume A pointer to a pre-allocated BVolume to be initialized to - refer to the next volume in the list of available volumes. - \return - - \c B_OK: Everything went fine. - - \c B_BAD_VALUE: The last volume in the list has already been returned. -*/ + +// Fills out the passed in BVolume object with the next available volume. status_t BVolumeRoster::GetNextVolume(BVolume *volume) { @@ -104,29 +62,16 @@ BVolumeRoster::GetNextVolume(BVolume *volume) return error; } -// Rewind -/*! \brief Rewinds the list of available volumes such that the next call to - GetNextVolume() will return the first element in the list. -*/ + +// Rewinds the list of available volumes back to the first item. void BVolumeRoster::Rewind() { fCookie = 0; } -// GetBootVolume -/*! \brief Returns the boot volume. - Currently, this function looks for the volume that is mounted at "/boot". - The only way to fool the system into thinking that there is not a boot - volume is to rename "/boot" -- but, please refrain from doing so...(:o( - - \param volume A pointer to a pre-allocated BVolume to be initialized to - refer to the boot volume. - \return - - \c B_OK: Everything went fine. - - an error code otherwise -*/ +// Fills out the passed in BVolume object with the boot volume. status_t BVolumeRoster::GetBootVolume(BVolume *volume) { @@ -145,27 +90,8 @@ BVolumeRoster::GetBootVolume(BVolume *volume) return error; } -// StartWatching -/*! \brief Starts watching the list of volumes available in the system. - Notifications are sent to the specified target whenever a volume is - mounted or unmounted. The format of the notification messages is - described under watch_node(). Actually BVolumeRoster just provides a - more convenient interface for it. - - If StartWatching() has been called before with another target and no - StopWatching() since, StopWatching() is called first, so that the former - target won't receive any notifications anymore. - - When the object is destroyed all watching has an end as well. - - \param messenger The target to which the notification messages shall be - sent. - \return - - \c B_OK: Everything went fine. - - \c B_BAD_VALUE: The supplied BMessenger is invalid. - - \c B_NO_MEMORY: Insufficient memory to carry out this operation. -*/ +// Starts watching the available volumes for changes. status_t BVolumeRoster::StartWatching(BMessenger messenger) { @@ -188,9 +114,8 @@ BVolumeRoster::StartWatching(BMessenger messenger) return error; } -// StopWatching -/*! \brief Stops volume watching initiated with StartWatching() before. -*/ + +// Stops watching volumes initiated by StartWatching(). void BVolumeRoster::StopWatching() { @@ -201,22 +126,20 @@ BVolumeRoster::StopWatching() } } -// Messenger -/*! \brief Returns a messenger to the target currently watching the volume - list. - \return A messenger to the target currently watching the volume list, or - an invalid messenger, if noone is currently watching. -*/ + +// Returns the messenger currently watching the volume list. BMessenger BVolumeRoster::Messenger() const { return (fTarget ? *fTarget : BMessenger()); } + // FBC void BVolumeRoster::_SeveredVRoster1() {} void BVolumeRoster::_SeveredVRoster2() {} + #ifdef USE_OPENBEOS_NAMESPACE } #endif diff --git a/src/libs/icon/IconUtils.cpp b/src/libs/icon/IconUtils.cpp index 0971c02007..81630e2bfc 100644 --- a/src/libs/icon/IconUtils.cpp +++ b/src/libs/icon/IconUtils.cpp @@ -1,11 +1,12 @@ /* - * Copyright 2006-2011, Haiku. All rights reserved. + * Copyright 2006-2013, Haiku. All rights reserved. * Distributed under the terms of the MIT License. * * Authors: - * Stephan Aßmus - * Ingo Weinhold - * John Scipione + * Stephan Aßmus, superstippi@gmx.de + * Axel Dörfler, axeld@pinc-software.de + * John Scipione, jscipione@gmail.com + * Ingo Weinhold, bonefish@cs.tu-berlin.de */ @@ -101,6 +102,70 @@ scale_bilinear(uint8* bits, int32 srcWidth, int32 srcHeight, int32 dstWidth, } +static void +scale_down(const uint8* srcBits, uint8* dstBits, int32 srcWidth, int32 srcHeight, + int32 dstWidth, int32 dstHeight) +{ + int32 l; + int32 c; + float t; + float u; + float tmp; + float d1, d2, d3, d4; + // coefficients + uint32 p1, p2, p3, p4; + // nearby pixels + uint8 red, green, blue, alpha; + // color components + + for (int32 i = 0; i < dstHeight; i++) { + for (int32 j = 0; j < dstWidth; j++) { + tmp = (float)(i) / (float)(dstHeight - 1) * (srcHeight - 1); + l = (int32)floorf(tmp); + if (l < 0) + l = 0; + else if (l >= srcHeight - 1) + l = srcHeight - 2; + u = tmp - l; + + tmp = (float)(j) / (float)(dstWidth - 1) * (srcWidth - 1); + c = (int32)floorf(tmp); + if (c < 0) + c = 0; + else if (c >= srcWidth - 1) + c = srcWidth - 2; + t = tmp - c; + + // coefficients + d1 = (1 - t) * (1 - u); + d2 = t * (1 - u); + d3 = t * u; + d4 = (1 - t) * u; + + // nearby pixels + p1 = *((uint32*)srcBits + (l * srcWidth) + c); + p2 = *((uint32*)srcBits + (l * srcWidth) + c + 1); + p3 = *((uint32*)srcBits + ((l + 1)* srcWidth) + c + 1); + p4 = *((uint32*)srcBits + ((l + 1)* srcWidth) + c); + + // color components + blue = (uint8)p1 * d1 + (uint8)p2 * d2 + (uint8)p3 * d3 + + (uint8)p4 * d4; + green = (uint8)(p1 >> 8) * d1 + (uint8)(p2 >> 8) * d2 + + (uint8)(p3 >> 8) * d3 + (uint8)(p4 >> 8) * d4; + red = (uint8)(p1 >> 16) * d1 + (uint8)(p2 >> 16) * d2 + + (uint8)(p3 >> 16) * d3 + (uint8)(p4 >> 16) * d4; + alpha = (uint8)(p1 >> 24) * d1 + (uint8)(p2 >> 24) * d2 + + (uint8)(p3 >> 24) * d3 + (uint8)(p4 >> 24) * d4; + + // destination RGBA pixel + *((uint32*)dstBits + (i * dstWidth) + j) + = (alpha << 24) | (red << 16) | (green << 8) | (blue); + } + } +} + + static void scale2x(const uint8* srcBits, uint8* dstBits, int32 srcWidth, int32 srcHeight, int32 srcBPR, int32 dstBPR) @@ -576,14 +641,33 @@ BIconUtils::ConvertFromCMAP8(const uint8* src, uint32 width, uint32 height, uint32 dstWidth = result->Bounds().IntegerWidth() + 1; uint32 dstHeight = result->Bounds().IntegerHeight() + 1; - if (dstWidth < width || dstHeight < height) { - // TODO: implement down scaling - return B_ERROR; - } - uint8* dst = (uint8*)result->Bits(); uint32 dstBPR = result->BytesPerRow(); + // check for downscaling or integer multiple scaling + if (dstWidth < width || dstHeight < height + || dstWidth == 2 * width && dstHeight == 2 * height + || dstWidth == 3 * width && dstHeight == 3 * height + || dstWidth == 4 * width && dstHeight == 4 * height) { + BBitmap* converted = new BBitmap(BRect(0, 0, width - 1, height - 1), + result->ColorSpace()); + converted->ImportBits(src, height * srcBPR, srcBPR, 0, B_CMAP8); + uint8* convertedBits = (uint8*)converted->Bits(); + int32 convertedBPR = converted->BytesPerRow(); + + if (dstWidth < width || dstHeight < height) + scale_down(convertedBits, dst, width, height, dstWidth, dstHeight); + else if (dstWidth == 2 * width && dstHeight == 2 * height) + scale2x(convertedBits, dst, width, height, convertedBPR, dstBPR); + else if (dstWidth == 3 * width && dstHeight == 3 * height) + scale3x(convertedBits, dst, width, height, convertedBPR, dstBPR); + else if (dstWidth == 4 * width && dstHeight == 4 * height) + scale4x(convertedBits, dst, width, height, convertedBPR, dstBPR); + + delete converted; + return B_OK; + } + const rgb_color* colorMap = system_colors()->color_list; if (colorMap == NULL) return B_NO_INIT; @@ -591,6 +675,7 @@ BIconUtils::ConvertFromCMAP8(const uint8* src, uint32 width, uint32 height, const uint8* srcStart = src; uint8* dstStart = dst; + // convert from B_CMAP8 to B_RGB(A)32 without scaling for (uint32 y = 0; y < height; y++) { uint32* d = (uint32*)dst; const uint8* s = src; @@ -605,35 +690,56 @@ BIconUtils::ConvertFromCMAP8(const uint8* src, uint32 width, uint32 height, dst += dstBPR; } + if (width == dstWidth && height == dstHeight) + return B_OK; + // reset src and dst back to their original locations src = srcStart; dst = dstStart; - if ((dstWidth == 2 * width && dstHeight == 2 * height) - || (dstWidth == 3 * width && dstHeight == 3 * height) - || (dstWidth == 4 * width && dstHeight == 4 * height)) { - // we can do some special scaling here - - // first convert to B_RGBA32 - BBitmap* converted - = new BBitmap(BRect(0, 0, width - 1, height - 1), - result->ColorSpace()); - converted->ImportBits(src, height * srcBPR, srcBPR, 0, B_CMAP8); - uint8* convertedBits = (uint8*)converted->Bits(); - int32 convertedBPR = converted->BytesPerRow(); - - // scale using the scale2x/scale3x/scale4x algorithm - if (dstWidth == 2 * width && dstHeight == 2 * height) - scale2x(convertedBits, dst, width, height, convertedBPR, dstBPR); - else if (dstWidth == 3 * width && dstHeight == 3 * height) - scale3x(convertedBits, dst, width, height, convertedBPR, dstBPR); - else if (dstWidth == 4 * width && dstHeight == 4 * height) - scale4x(convertedBits, dst, width, height, convertedBPR, dstBPR); - - // cleanup - delete converted; + if (dstWidth > width && dstHeight > height + && dstWidth < 2 * width && dstHeight < 2 * height) { + // scale2x then downscale + BBitmap* temp = new BBitmap(BRect(0, 0, width * 2 - 1, height * 2 - 1), + result->ColorSpace()); + uint8* tempBits = (uint8*)temp->Bits(); + uint32 tempBPR = temp->BytesPerRow(); + scale2x(dst, tempBits, width, height, dstBPR, tempBPR); + scale_down(tempBits, dst, width * 2, height * 2, dstWidth, dstHeight); + delete temp; + } else if (dstWidth > 2 * width && dstHeight > 2 * height + && dstWidth < 3 * width && dstHeight < 3 * height) { + // scale3x then downscale + BBitmap* temp = new BBitmap(BRect(0, 0, width * 3 - 1, height * 3 - 1), + result->ColorSpace()); + uint8* tempBits = (uint8*)temp->Bits(); + uint32 tempBPR = temp->BytesPerRow(); + scale3x(dst, tempBits, width, height, dstBPR, tempBPR); + scale_down(tempBits, dst, width * 3, height * 3, dstWidth, dstHeight); + delete temp; + } else if (dstWidth > 3 * width && dstHeight > 3 * height + && dstWidth < 4 * width && dstHeight < 4 * height) { + // scale4x then downscale + BBitmap* temp = new BBitmap(BRect(0, 0, width * 4 - 1, height * 4 - 1), + result->ColorSpace()); + uint8* tempBits = (uint8*)temp->Bits(); + uint32 tempBPR = temp->BytesPerRow(); + scale4x(dst, tempBits, width, height, dstBPR, tempBPR); + scale_down(tempBits, dst, width * 3, height * 3, dstWidth, dstHeight); + delete temp; + } else if (dstWidth > 4 * width && dstHeight > 4 * height) { + // scale4x then bilinear + BBitmap* temp = new BBitmap(BRect(0, 0, width * 4 - 1, height * 4 - 1), + result->ColorSpace()); + uint8* tempBits = (uint8*)temp->Bits(); + uint32 tempBPR = temp->BytesPerRow(); + scale4x(dst, tempBits, width, height, dstBPR, tempBPR); + result->ImportBits(tempBits, height * tempBPR, tempBPR, 0, + temp->ColorSpace()); + scale_bilinear(dst, width, height, dstWidth, dstHeight, dstBPR); + delete temp; } else { - // bilinear scaling + // fall back to bilinear scaling scale_bilinear(dst, width, height, dstWidth, dstHeight, dstBPR); } diff --git a/src/preferences/appearance/APRView.cpp b/src/preferences/appearance/APRView.cpp index 33b59d5d3a..6b7c1e0873 100644 --- a/src/preferences/appearance/APRView.cpp +++ b/src/preferences/appearance/APRView.cpp @@ -25,9 +25,9 @@ #include "APRWindow.h" #include "defs.h" -#include "ColorWell.h" -#include "ColorWhichItem.h" +#include "ColorPreview.h" #include "ColorSet.h" +#include "ColorWhichItem.h" #undef B_TRANSLATION_CONTEXT @@ -87,8 +87,8 @@ APRView::APRView(const char* name) } BRect wellrect(0, 0, 50, 50); - fColorWell = new ColorWell(wellrect, new BMessage(COLOR_DROPPED), 0); - fColorWell->SetExplicitAlignment(BAlignment(B_ALIGN_HORIZONTAL_CENTER, + fColorPreview = new ColorPreview(wellrect, new BMessage(COLOR_DROPPED), 0); + fColorPreview->SetExplicitAlignment(BAlignment(B_ALIGN_HORIZONTAL_CENTER, B_ALIGN_BOTTOM)); fPicker = new BColorControl(B_ORIGIN, B_CELLS_32x8, 8.0, @@ -100,14 +100,14 @@ APRView::APRView(const char* name) .Add(fScrollView) .Add(BSpaceLayoutItem::CreateVerticalStrut(5)) .Add(BGroupLayoutBuilder(B_HORIZONTAL) - .Add(fColorWell) + .Add(fColorPreview) .Add(BSpaceLayoutItem::CreateHorizontalStrut(5)) .Add(fPicker) ) .SetInsets(10, 10, 10, 10) ); - fColorWell->Parent()->SetExplicitMaxSize( + fColorPreview->Parent()->SetExplicitMaxSize( BSize(B_SIZE_UNSET, fPicker->Bounds().Height())); fAttrList->SetSelectionMessage(new BMessage(ATTRIBUTE_CHOSEN)); } @@ -123,7 +123,7 @@ APRView::AttachedToWindow() { fPicker->SetTarget(this); fAttrList->SetTarget(this); - fColorWell->SetTarget(this); + fColorPreview->SetTarget(this); fAttrList->Select(0); } @@ -257,8 +257,8 @@ APRView::_UpdateControls() } fPicker->SetValue(color); - fColorWell->SetColor(color); - fColorWell->Invalidate(); + fColorPreview->SetColor(color); + fColorPreview->Invalidate(); } diff --git a/src/preferences/appearance/APRView.h b/src/preferences/appearance/APRView.h index 1cfd6003da..41b65cd54d 100644 --- a/src/preferences/appearance/APRView.h +++ b/src/preferences/appearance/APRView.h @@ -31,9 +31,8 @@ #include "ColorSet.h" -class ColorWell; class APRWindow; - +class ColorPreview; class APRView : public BView { public: @@ -65,11 +64,11 @@ private: BScrollView* fScrollView; - ColorWell* fColorWell; + ColorPreview* fColorPreview; ColorSet fCurrentSet; ColorSet fPrevSet; ColorSet fDefaultSet; }; -#endif +#endif // APR_VIEW_H_ diff --git a/src/preferences/appearance/ColorPreview.cpp b/src/preferences/appearance/ColorPreview.cpp new file mode 100644 index 0000000000..6dcbc04e37 --- /dev/null +++ b/src/preferences/appearance/ColorPreview.cpp @@ -0,0 +1,167 @@ +/* + * Copyright 2002-2013 Haiku Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * DarkWyrm, darkwyrm@earthlink.net + * John Scipione, jscipione@gmail.com + */ + + +#include "ColorPreview.h" + + +ColorPreview::ColorPreview(BRect frame, BMessage* message, + uint32 resizingMode, uint32 flags) + : + BView(frame,"ColorPreview", resizingMode, flags | B_WILL_DRAW) +{ + SetViewColor(B_TRANSPARENT_COLOR); + SetLowColor(0, 0, 0); + invoker = new BInvoker(message, this); + disabledcol.red = 128; + disabledcol.green = 128; + disabledcol.blue = 128; + disabledcol.alpha = 255; + is_enabled = true; + is_rect = true; +} + + +ColorPreview::~ColorPreview(void) +{ + delete invoker; +} + + +void +ColorPreview::Draw(BRect update) +{ + rgb_color color; + if (is_enabled) + color = currentcol; + else + color = disabledcol; + + if (is_rect) { + if (is_enabled) { + rgb_color background = ui_color(B_PANEL_BACKGROUND_COLOR); + rgb_color shadow = tint_color(background, B_DARKEN_1_TINT); + rgb_color darkShadow = tint_color(background, B_DARKEN_3_TINT); + rgb_color light = tint_color(background, B_LIGHTEN_MAX_TINT); + + BRect bounds(Bounds()); + + BeginLineArray(4); + AddLine(BPoint(bounds.left, bounds.bottom), + BPoint(bounds.left, bounds.top), shadow); + AddLine(BPoint(bounds.left + 1.0, bounds.top), + BPoint(bounds.right, bounds.top), shadow); + AddLine(BPoint(bounds.right, bounds.top + 1.0), + BPoint(bounds.right, bounds.bottom), light); + AddLine(BPoint(bounds.right - 1.0, bounds.bottom), + BPoint(bounds.left + 1.0, bounds.bottom), light); + EndLineArray(); + bounds.InsetBy(1.0, 1.0); + + BeginLineArray(4); + AddLine(BPoint(bounds.left, bounds.bottom), + BPoint(bounds.left, bounds.top), darkShadow); + AddLine(BPoint(bounds.left + 1.0, bounds.top), + BPoint(bounds.right, bounds.top), darkShadow); + AddLine(BPoint(bounds.right, bounds.top + 1.0), + BPoint(bounds.right, bounds.bottom), background); + AddLine(BPoint(bounds.right - 1.0, bounds.bottom), + BPoint(bounds.left + 1.0, bounds.bottom), background); + EndLineArray(); + bounds.InsetBy(1.0, 1.0); + + SetHighColor(color); + FillRect(bounds); + } else { + SetHighColor(color); + FillRect(Bounds()); + } + } else { + // fill background + SetHighColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + FillRect(update); + + SetHighColor(color); + FillEllipse(Bounds()); + if (is_enabled) + StrokeEllipse(Bounds(), B_SOLID_LOW); + } +} + + +void +ColorPreview::MessageReceived(BMessage* message) +{ + // If we received a dropped message, see if it contains color data + if (message->WasDropped()) { + rgb_color* col; + uint8* ptr; + ssize_t size; + if (message->FindData("RGBColor", (type_code)'RGBC', + (const void**)&ptr,&size) == B_OK) { + col = (rgb_color*)ptr; + SetHighColor(*col); + } + } + + BView::MessageReceived(message); +} + + +void +ColorPreview::SetEnabled(bool value) +{ + if (is_enabled != value) { + is_enabled = value; + Invalidate(); + } +} + + +void +ColorPreview::SetTarget(BHandler* target) +{ + invoker->SetTarget(target); +} + + +rgb_color +ColorPreview::Color(void) const +{ + return currentcol; +} + + +void +ColorPreview::SetColor(rgb_color col) +{ + SetHighColor(col); + currentcol = col; + Draw(Bounds()); + invoker->Invoke(); +} + + +void +ColorPreview::SetColor(uint8 r,uint8 g, uint8 b) +{ + SetHighColor(r,g,b); + currentcol.red = r; + currentcol.green = g; + currentcol.blue = b; + Draw(Bounds()); + invoker->Invoke(); +} + + +void +ColorPreview::SetMode(bool is_rectangle) +{ + is_rect = is_rectangle; +} diff --git a/src/preferences/appearance/ColorPreview.h b/src/preferences/appearance/ColorPreview.h new file mode 100644 index 0000000000..a293e40ceb --- /dev/null +++ b/src/preferences/appearance/ColorPreview.h @@ -0,0 +1,47 @@ +/* + * Copyright 2002-2013 Haiku Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * DarkWyrm, darkwyrm@earthlink.net + * John Scipione, jscipione@gmail.com + */ +#ifndef COLOR_PREVIEW_H_ +#define COLOR_PREVIEW_H_ + + +#include +#include +#include + + +class ColorPreview : public BView +{ +public: + ColorPreview(BRect frame, BMessage *msg, + uint32 resizingMode = B_FOLLOW_LEFT + | B_FOLLOW_TOP, + uint32 flags = B_WILL_DRAW); + ~ColorPreview(void); + + virtual void Draw(BRect update); + virtual void MessageReceived(BMessage* message); + virtual void SetTarget(BHandler* target); + virtual void SetEnabled(bool value); + + rgb_color Color(void) const; + void SetColor(rgb_color col); + void SetColor(uint8 r,uint8 g, uint8 b); + + void SetMode(bool is_rectangle); + +protected: + BInvoker* invoker; + + bool is_enabled; + bool is_rect; + rgb_color disabledcol; + rgb_color currentcol; +}; + +#endif // COLOR_PREVIEW_H_ diff --git a/src/preferences/appearance/ColorWell.cpp b/src/preferences/appearance/ColorWell.cpp deleted file mode 100644 index 2a5e5eab0c..0000000000 --- a/src/preferences/appearance/ColorWell.cpp +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright 2002-2006, Haiku. All rights reserved. - * Distributed under the terms of the MIT License. - * - * Authors: - * DarkWyrm (darkwyrm@earthlink.net) - */ -#include "ColorWell.h" - -ColorWell::ColorWell(BRect frame, BMessage *msg, uint32 resizingMode, uint32 flags) - : BView(frame,"ColorWell", resizingMode, flags | B_WILL_DRAW) -{ - SetViewColor(B_TRANSPARENT_COLOR); - SetLowColor(0,0,0); - invoker=new BInvoker(msg,this); - disabledcol.red=128; - disabledcol.green=128; - disabledcol.blue=128; - disabledcol.alpha=255; - is_enabled=true; - is_rect = true; -} - -ColorWell::~ColorWell(void) -{ - delete invoker; -} - -void -ColorWell::SetTarget(BHandler *tgt) -{ - invoker->SetTarget(tgt); -} - -void -ColorWell::SetColor(rgb_color col) -{ - SetHighColor(col); - currentcol=col; - Draw(Bounds()); - invoker->Invoke(); -} - -void -ColorWell::SetColor(uint8 r,uint8 g, uint8 b) -{ - SetHighColor(r,g,b); - currentcol.red=r; - currentcol.green=g; - currentcol.blue=b; - Draw(Bounds()); - invoker->Invoke(); -} - -void -ColorWell::MessageReceived(BMessage *msg) -{ - // If we received a dropped message, try to see if it has color data - // in it - if(msg->WasDropped()) { - rgb_color *col; - uint8 *ptr; - ssize_t size; - if(msg->FindData("RGBColor",(type_code)'RGBC', - (const void**)&ptr,&size)==B_OK) { - col=(rgb_color*)ptr; - SetHighColor(*col); - } - } - - // The default - BView::MessageReceived(msg); -} - -void -ColorWell::SetEnabled(bool value) -{ - if(is_enabled!=value) { - is_enabled=value; - Invalidate(); - } -} - -void -ColorWell::Draw(BRect update) -{ - rgb_color color; - if (is_enabled) - color = currentcol; - else - color = disabledcol; - - if(is_rect) { - if(is_enabled) { - BRect r(Bounds()); - SetHighColor(184,184,184); - StrokeRect(r); - - SetHighColor(255,255,255); - StrokeLine(BPoint(r.right, r.top+1), r.RightBottom()); - - r.InsetBy(1,1); - - SetHighColor(216,216,216); - StrokeLine(r.RightTop(), r.RightBottom()); - - SetHighColor(96,96,96); - StrokeLine(r.LeftTop(), r.RightTop()); - StrokeLine(r.LeftTop(), r.LeftBottom()); - - r.InsetBy(1, 1); - SetHighColor(color); - FillRect(r); - } else { - SetHighColor(color); - FillRect(Bounds()); - } - } - else { - // fill background - SetHighColor(ui_color(B_PANEL_BACKGROUND_COLOR)); - FillRect(update); - - SetHighColor(color); - FillEllipse(Bounds()); - if(is_enabled) - StrokeEllipse(Bounds(),B_SOLID_LOW); - } -} - -rgb_color -ColorWell::Color(void) const -{ - return currentcol; -} - -void -ColorWell::SetMode(bool is_rectangle) -{ - is_rect=is_rectangle; -} diff --git a/src/preferences/appearance/ColorWell.h b/src/preferences/appearance/ColorWell.h deleted file mode 100644 index 92c2ea5f20..0000000000 --- a/src/preferences/appearance/ColorWell.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2002-2006, Haiku. All rights reserved. - * Distributed under the terms of the MIT License. - * - * Authors: - * DarkWyrm (darkwyrm@earthlink.net) - */ -#ifndef COLORWELL_H_ -#define COLORWELL_H_ - -#include -#include -#include - -class ColorWell : public BView -{ -public: - ColorWell(BRect frame, BMessage *msg, - uint32 resizingMode = B_FOLLOW_LEFT | B_FOLLOW_TOP, - uint32 flags = B_WILL_DRAW); - ~ColorWell(void); - void SetColor(rgb_color col); - rgb_color Color(void) const; - void SetColor(uint8 r,uint8 g, uint8 b); - virtual void MessageReceived(BMessage *msg); - virtual void Draw(BRect update); - virtual void SetTarget(BHandler *tgt); - virtual void SetEnabled(bool value); - void SetMode(bool is_rectangle); -protected: - BInvoker *invoker; - bool is_enabled, is_rect; - rgb_color disabledcol, currentcol; -}; - -#endif diff --git a/src/preferences/appearance/FakeScrollBar.cpp b/src/preferences/appearance/FakeScrollBar.cpp index fdbd1d1f16..e8a792928e 100644 --- a/src/preferences/appearance/FakeScrollBar.cpp +++ b/src/preferences/appearance/FakeScrollBar.cpp @@ -99,16 +99,16 @@ FakeScrollBar::Draw(BRect updateRect) BRect buttonFrame(bounds.left, bounds.top, bounds.left + bounds.Height(), bounds.bottom); - _DrawArrowButton(ARROW_LEFT, fDoubleArrows, buttonFrame, updateRect); + _DrawArrowButton(ARROW_LEFT, buttonFrame, updateRect); if (fDoubleArrows) { buttonFrame.OffsetBy(bounds.Height() + 1, 0.0); - _DrawArrowButton(ARROW_RIGHT, fDoubleArrows, buttonFrame, + _DrawArrowButton(ARROW_RIGHT, buttonFrame, updateRect); buttonFrame.OffsetTo(bounds.right - ((bounds.Height() * 2) + 1), bounds.top); - _DrawArrowButton(ARROW_LEFT, fDoubleArrows, buttonFrame, + _DrawArrowButton(ARROW_LEFT, buttonFrame, updateRect); thumbBG.left += bounds.Height() * 2 + 2; @@ -119,7 +119,7 @@ FakeScrollBar::Draw(BRect updateRect) } buttonFrame.OffsetTo(bounds.right - bounds.Height(), bounds.top); - _DrawArrowButton(ARROW_RIGHT, fDoubleArrows, buttonFrame, updateRect); + _DrawArrowButton(ARROW_RIGHT, buttonFrame, updateRect); SetDrawingMode(B_OP_COPY); @@ -261,63 +261,21 @@ FakeScrollBar::SetFromScrollBarInfo(const scroll_bar_info &info) void -FakeScrollBar::_DrawArrowButton(int32 direction, bool doubleArrows, BRect r, +FakeScrollBar::_DrawArrowButton(int32 direction, BRect rect, const BRect& updateRect) { - if (!updateRect.Intersects(r)) + if (!updateRect.Intersects(rect)) return; - rgb_color c = ui_color(B_PANEL_BACKGROUND_COLOR); - rgb_color light = tint_color(c, B_LIGHTEN_MAX_TINT); - rgb_color dark = tint_color(c, B_DARKEN_1_TINT); - rgb_color darker = tint_color(c, B_DARKEN_2_TINT); - rgb_color normal = c; - rgb_color arrow = tint_color(c, - (B_DARKEN_MAX_TINT + B_DARKEN_4_TINT) / 2.0); + uint32 flags = 0; - BPoint tri1, tri2, tri3; - float hInset = r.Width() / 3; - float vInset = r.Height() / 3; - r.InsetBy(hInset, vInset); + rgb_color baseColor = tint_color(ui_color(B_PANEL_BACKGROUND_COLOR), + B_LIGHTEN_1_TINT); - switch (direction) { - case ARROW_LEFT: - tri1.Set(r.right, r.top); - tri2.Set(r.right - r.Width() / 1.33, (r.top + r.bottom + 1) / 2); - tri3.Set(r.right, r.bottom + 1); - break; + be_control_look->DrawButtonBackground(this, rect, updateRect, baseColor, + flags, BControlLook::B_ALL_BORDERS, B_HORIZONTAL); - case ARROW_RIGHT: - tri1.Set(r.left, r.bottom + 1); - tri2.Set(r.left + r.Width() / 1.33, (r.top + r.bottom + 1) / 2); - tri3.Set(r.left, r.top); - break; - - case ARROW_UP: - tri1.Set(r.left, r.bottom); - tri2.Set((r.left + r.right + 1) / 2, r.bottom - r.Height() / 1.33); - tri3.Set(r.right + 1, r.bottom); - break; - - default: - tri1.Set(r.left, r.top); - tri2.Set((r.left + r.right + 1) / 2, r.top + r.Height() / 1.33); - tri3.Set(r.right + 1, r.top); - break; - } - - r.InsetBy(-(hInset - 1), -(vInset - 1)); - BRect temp(r.InsetByCopy(-1, -1)); - be_control_look->DrawButtonBackground(this, temp, updateRect, - normal, 0, BControlLook::B_ALL_BORDERS, B_HORIZONTAL); - - BShape arrowShape; - arrowShape.MoveTo(tri1); - arrowShape.LineTo(tri2); - arrowShape.LineTo(tri3); - - SetHighColor(arrow); - SetPenSize(ceilf(hInset / 2.0)); - StrokeShape(&arrowShape); - SetPenSize(1.0); + rect.InsetBy(-1, -1); + be_control_look->DrawArrowShape(this, rect, updateRect, + baseColor, direction, flags, B_DARKEN_MAX_TINT); } diff --git a/src/preferences/appearance/FakeScrollBar.h b/src/preferences/appearance/FakeScrollBar.h index 74e034b4cd..c02571ed82 100644 --- a/src/preferences/appearance/FakeScrollBar.h +++ b/src/preferences/appearance/FakeScrollBar.h @@ -34,8 +34,7 @@ public: void SetFromScrollBarInfo(const scroll_bar_info &info); private: - void _DrawArrowButton(int32 direction, - bool doubleArrows, BRect r, + void _DrawArrowButton(int32 direction, BRect r, const BRect& updateRect); bool fDrawArrows; diff --git a/src/preferences/appearance/Jamfile b/src/preferences/appearance/Jamfile index 1c287a91ac..ca3eb7dcc4 100644 --- a/src/preferences/appearance/Jamfile +++ b/src/preferences/appearance/Jamfile @@ -15,8 +15,8 @@ Preference Appearance : FontView.cpp APRView.cpp APRWindow.cpp + ColorPreview.cpp ColorSet.cpp - ColorWell.cpp ColorWhichItem.cpp # These are currently disabled while everything else is being worked on @@ -38,11 +38,10 @@ DoCatalogs Appearance : AntialiasingSettingsView.cpp APRView.cpp APRWindow.cpp + ColorPreview.cpp ColorSet.cpp - ColorWell.cpp ColorWhichItem.cpp LookAndFeelSettingsView.cpp FontView.cpp FontSelectionView.cpp ; - diff --git a/src/preferences/appearance/LookAndFeelSettingsView.cpp b/src/preferences/appearance/LookAndFeelSettingsView.cpp index 5a6b12c455..eb048aaa32 100644 --- a/src/preferences/appearance/LookAndFeelSettingsView.cpp +++ b/src/preferences/appearance/LookAndFeelSettingsView.cpp @@ -74,7 +74,7 @@ LookAndFeelSettingsView::LookAndFeelSettingsView(const char* name) // Decorator menu _BuildDecorMenu(); fDecorMenuField = new BMenuField("decorator", - B_TRANSLATE("Window decorator:"), fDecorMenu); + B_TRANSLATE("Decorator:"), fDecorMenu); fDecorInfoButton = new BButton(B_TRANSLATE("About"), new BMessage(kMsgDecorInfo)); @@ -179,13 +179,14 @@ LookAndFeelSettingsView::MessageReceived(BMessage *msg) break; BString authorsText(decor->Authors().String()); - authorsText.ReplaceAll(", ", "\n "); + authorsText.ReplaceAll(", ", "\n\t"); - BString infoText("Name: %decorName\n" - "Authors:\n %decorAuthors\n" + BString infoText(B_TRANSLATE("%decorName\n\n" + "Authors:\n\t%decorAuthors\n\n" "URL: %decorURL\n" - "License: %decorLic\n" - "Description:\n %decorDesc\n"); + "License: %decorLic\n\n" + "%decorDesc\n")); + infoText.ReplaceFirst("%decorName", decor->Name().String()); infoText.ReplaceFirst("%decorAuthors", authorsText.String()); @@ -193,7 +194,7 @@ LookAndFeelSettingsView::MessageReceived(BMessage *msg) infoText.ReplaceFirst("%decorURL", decor->SupportURL().String()); infoText.ReplaceFirst("%decorDesc", decor->ShortDescription().String()); - BAlert *infoAlert = new BAlert(B_TRANSLATE("About Decorator"), + BAlert *infoAlert = new BAlert(B_TRANSLATE("About decorator"), infoText.String(), B_TRANSLATE("OK")); infoAlert->SetFlags(infoAlert->Flags() | B_CLOSE_ON_ESCAPE); infoAlert->Go(); diff --git a/src/preferences/bluetooth/BluetoothMain.cpp b/src/preferences/bluetooth/BluetoothMain.cpp index 0b71630b3f..3451ecb656 100644 --- a/src/preferences/bluetooth/BluetoothMain.cpp +++ b/src/preferences/bluetooth/BluetoothMain.cpp @@ -77,7 +77,7 @@ BluetoothApplication::MessageReceived(BMessage* message) BMessageRunner::StartSending(be_app_messenger, new BMessage('Xtmp'), 2 * 1000000, 1); } else { - fWindow = new BluetoothWindow(BRect(100, 100, 550, 420)); + fWindow = new BluetoothWindow(BRect(100, 100, 750, 420)); fWindow->Show(); } break; diff --git a/src/preferences/bluetooth/BluetoothSettings.cpp b/src/preferences/bluetooth/BluetoothSettings.cpp new file mode 100644 index 0000000000..2f3bc59d86 --- /dev/null +++ b/src/preferences/bluetooth/BluetoothSettings.cpp @@ -0,0 +1,57 @@ +/* + * Copyright 2008-2009, Oliver Ruiz Dorantes, + * Copyright 2012-2013, Tri-Edge AI + * + * All rights reserved. Distributed under the terms of the MIT license. + */ + +#include "BluetoothSettings.h" + +BluetoothSettings::BluetoothSettings() +{ + find_directory(B_USER_SETTINGS_DIRECTORY, &fPath); + fPath.Append("Bluetooth_settings", true); +} + + +BluetoothSettings::~BluetoothSettings() +{ + +} + + +void +BluetoothSettings::Defaults() +{ + Data.PickedDevice = bdaddrUtils::NullAddress(); + Data.LocalDeviceClass = DeviceClass(); +} + + +void +BluetoothSettings::Load() +{ + fFile = new BFile(fPath.Path(), B_READ_ONLY); + + if (fFile->InitCheck() == B_OK) { + fFile->Read(&Data, sizeof(Data)); + // TODO: Add more settings here. + } else + Defaults(); + + delete fFile; +} + + +void +BluetoothSettings::Save() +{ + fFile = new BFile(fPath.Path(), B_WRITE_ONLY | B_CREATE_FILE); + + if (fFile->InitCheck() == B_OK) { + fFile->Write(&Data, sizeof(Data)); + // TODO: Add more settings here. + } + + delete fFile; +} diff --git a/src/preferences/bluetooth/BluetoothSettings.h b/src/preferences/bluetooth/BluetoothSettings.h new file mode 100644 index 0000000000..0ba558b150 --- /dev/null +++ b/src/preferences/bluetooth/BluetoothSettings.h @@ -0,0 +1,38 @@ +/* + * Copyright 2008-2009, Oliver Ruiz Dorantes, + * Copyright 2012-2013, Tri-Edge AI + * + * All rights reserved. Distributed under the terms of the MIT license. + */ + +#ifndef BLUETOOTH_SETTINGS_H +#define BLUETOOTH_SETTINGS_H + +#include +#include + +#include +#include +#include + +class BluetoothSettings +{ +public: + struct { + bdaddr_t PickedDevice; + DeviceClass LocalDeviceClass; + } Data; + + BluetoothSettings(); + ~BluetoothSettings(); + + void Defaults(); + void Load(); + void Save(); + +private: + BPath fPath; + BFile* fFile; +}; + +#endif // BLUETOOTH_SETTINGS_H diff --git a/src/preferences/bluetooth/BluetoothSettingsView.cpp b/src/preferences/bluetooth/BluetoothSettingsView.cpp index b9ba836558..54a1864094 100644 --- a/src/preferences/bluetooth/BluetoothSettingsView.cpp +++ b/src/preferences/bluetooth/BluetoothSettingsView.cpp @@ -1,11 +1,18 @@ /* - * Copyright 2008-09, Oliver Ruiz Dorantes, + * Copyright 2008-2009, Oliver Ruiz Dorantes + * Copyright 2012-2013, Tri-Edge AI, + * * All rights reserved. Distributed under the terms of the MIT License. */ + #include "BluetoothSettingsView.h" -#include -#include +#include "defs.h" +#include "BluetoothSettings.h" +#include "BluetoothWindow.h" +#include "ExtendedLocalDeviceView.h" + +#include #include #include @@ -19,12 +26,8 @@ #include #include -#include -#include "ExtendedLocalDeviceView.h" - -#include "defs.h" -#include "BluetoothWindow.h" - +#include +#include #undef B_TRANSLATION_CONTEXT #define B_TRANSLATION_CONTEXT "Settings view" @@ -45,13 +48,15 @@ static const char* kLaptopLabel = B_TRANSLATE_MARK("Laptop"); static const char* kHandheldLabel = B_TRANSLATE_MARK("Handheld"); static const char* kPhoneLabel = B_TRANSLATE_MARK("Smart phone"); - // #pragma mark - BluetoothSettingsView::BluetoothSettingsView(const char* name) - : BView(name, 0), + : + BView(name, 0), fLocalDevicesMenu(NULL) { + fSettings.Load(); + _BuildConnectionPolicy(); fPolicyMenuField = new BMenuField("policy", B_TRANSLATE("Incoming connections policy:"), fPolicyMenu); @@ -65,10 +70,7 @@ BluetoothSettingsView::BluetoothSettingsView(const char* name) fInquiryTimeControl->SetHashMarkCount(255 / 15); fInquiryTimeControl->SetEnabled(true); - // hinting menu - _BuildClassMenu(); - fClassMenuField = new BMenuField("class", B_TRANSLATE("Identify host as:"), - fClassMenu); + fExtDeviceView = new ExtendedLocalDeviceView(BRect(0, 0, 5, 5), NULL); // localdevices menu _BuildLocalDevicesMenu(); @@ -76,13 +78,25 @@ BluetoothSettingsView::BluetoothSettingsView(const char* name) B_TRANSLATE("Local devices found on system:"), fLocalDevicesMenu); - fExtDeviceView = new ExtendedLocalDeviceView(BRect(0, 0, 5, 5), NULL); - SetLayout(new BGroupLayout(B_VERTICAL)); + if (ActiveLocalDevice != NULL) { + fExtDeviceView->SetLocalDevice(ActiveLocalDevice); + fExtDeviceView->SetEnabled(true); + + DeviceClass rememberedClass = ActiveLocalDevice->GetDeviceClass(); + + if (!rememberedClass.IsUnknownDeviceClass()) + fSettings.Data.LocalDeviceClass = rememberedClass; + } + + // hinting menu + _BuildClassMenu(); + fClassMenuField = new BMenuField("class", B_TRANSLATE("Identify host as:"), + fClassMenu); + // controls pane AddChild(BGridLayoutBuilder(10, 10) - .Add(fClassMenuField->CreateLabelLayoutItem(), 0, 0) .Add(fClassMenuField->CreateMenuBarLayoutItem(), 1, 0) @@ -107,7 +121,7 @@ BluetoothSettingsView::BluetoothSettingsView(const char* name) BluetoothSettingsView::~BluetoothSettingsView() { - + fSettings.Save(); } @@ -133,44 +147,52 @@ BluetoothSettingsView::MessageReceived(BMessage* message) case kMsgLocalSwitched: { LocalDevice* lDevice; - if (message->FindPointer("LocalDevice", (void**) &lDevice) == B_OK) { - // Device integrity should be rechecked - fExtDeviceView->SetLocalDevice(lDevice); - fExtDeviceView->SetEnabled(true); - ActiveLocalDevice = lDevice; + + if (message->FindPointer("LocalDevice", + (void**)&lDevice) == B_OK) { + + _MarkLocalDevice(lDevice); } + + break; } - break; -/* - To be fixed :) + // TODO: To be fixed. :) + + /* case kMsgSetConnectionPolicy: { //uint8 Policy; //if (message->FindInt8("Policy", (int8*)&Policy) == B_OK) break; } - + case kMsgSetInquiryTime: { break; - }*/ - + } + */ case kMsgSetDeviceClass: { uint8 deviceClass; - if (message->FindInt8("DeviceClass", (int8*)&deviceClass) == B_OK) { + + if (message->FindInt8("DeviceClass", + (int8*)&deviceClass) == B_OK) { + if (deviceClass == 5) _SetDeviceClass(2, 3, 0x72); else _SetDeviceClass(1, deviceClass, 0x72); } + break; } - case kMsgRefresh: + { _BuildLocalDevicesMenu(); fLocalDevicesMenu->SetTargetForItems(this); - break; + + break; + } default: BView::MessageReceived(message); } @@ -178,17 +200,18 @@ BluetoothSettingsView::MessageReceived(BMessage* message) bool -BluetoothSettingsView::_SetDeviceClass(uint8 major, uint8 minor, uint16 service) +BluetoothSettingsView::_SetDeviceClass(uint8 major, uint8 minor, + uint16 service) { bool haveRun = true; - - DeviceClass devClass; - devClass.SetRecord(major, minor, service); + + fSettings.Data.LocalDeviceClass.SetRecord(major, minor, service); + if (ActiveLocalDevice != NULL) - ActiveLocalDevice->SetDeviceClass(devClass); + ActiveLocalDevice->SetDeviceClass(fSettings.Data.LocalDeviceClass); else haveRun = false; - + return haveRun; } @@ -217,11 +240,9 @@ BluetoothSettingsView::_BuildConnectionPolicy() fPolicyMenu->AddItem(item); } - void BluetoothSettingsView::_BuildClassMenu() { - BMessage* message = NULL; BMenuItem* item = NULL; @@ -232,25 +253,45 @@ BluetoothSettingsView::_BuildClassMenu() item = new BMenuItem(B_TRANSLATE_NOCOLLECT(kDesktopLabel), message); fClassMenu->AddItem(item); + if (fSettings.Data.LocalDeviceClass.MajorDeviceClass() == 1 && + fSettings.Data.LocalDeviceClass.MinorDeviceClass() == 1) + item->SetMarked(true); + message = new BMessage(kMsgSetDeviceClass); message->AddInt8("DeviceClass", 2); item = new BMenuItem(B_TRANSLATE_NOCOLLECT(kServerLabel), message); fClassMenu->AddItem(item); + if (fSettings.Data.LocalDeviceClass.MajorDeviceClass() == 1 && + fSettings.Data.LocalDeviceClass.MinorDeviceClass() == 2) + item->SetMarked(true); + message = new BMessage(kMsgSetDeviceClass); message->AddInt8("DeviceClass", 3); item = new BMenuItem(B_TRANSLATE_NOCOLLECT(kLaptopLabel), message); fClassMenu->AddItem(item); + if (fSettings.Data.LocalDeviceClass.MajorDeviceClass() == 1 && + fSettings.Data.LocalDeviceClass.MinorDeviceClass() == 3) + item->SetMarked(true); + message = new BMessage(kMsgSetDeviceClass); message->AddInt8("DeviceClass", 4); item = new BMenuItem(B_TRANSLATE_NOCOLLECT(kHandheldLabel), message); fClassMenu->AddItem(item); + if (fSettings.Data.LocalDeviceClass.MajorDeviceClass() == 1 && + fSettings.Data.LocalDeviceClass.MinorDeviceClass() == 4) + item->SetMarked(true); + message = new BMessage(kMsgSetDeviceClass); message->AddInt8("DeviceClass", 5); item = new BMenuItem(B_TRANSLATE_NOCOLLECT(kPhoneLabel), message); fClassMenu->AddItem(item); + + if (fSettings.Data.LocalDeviceClass.MajorDeviceClass() == 2 && + fSettings.Data.LocalDeviceClass.MinorDeviceClass() == 3) + item->SetMarked(true); } @@ -260,20 +301,47 @@ BluetoothSettingsView::_BuildLocalDevicesMenu() LocalDevice* lDevice; if (!fLocalDevicesMenu) - fLocalDevicesMenu = new BPopUpMenu(B_TRANSLATE("Pick LocalDevice...")); + fLocalDevicesMenu = new BPopUpMenu(B_TRANSLATE("Pick device...")); - for (uint32 index = 0; index < LocalDevice::GetLocalDeviceCount(); index++) { + while (fLocalDevicesMenu->CountItems() > 0) { + BMenuItem* item = fLocalDevicesMenu->RemoveItem(0L); + if (item != NULL) { + delete item; + } + } + + ActiveLocalDevice = NULL; + + for (uint32 i = 0; i < LocalDevice::GetLocalDeviceCount(); i++) { lDevice = LocalDevice::GetLocalDevice(); - if (lDevice != NULL) { - // TODO Check if they already exists + if (lDevice != NULL) { BMessage* message = new BMessage(kMsgLocalSwitched); message->AddPointer("LocalDevice", lDevice); - BMenuItem* item = new BMenuItem((lDevice->GetFriendlyName().String()), - message); + BMenuItem* item = new BMenuItem( + (lDevice->GetFriendlyName().String()), message); + + if (bdaddrUtils::Compare(lDevice->GetBluetoothAddress(), + fSettings.Data.PickedDevice)) { + + item->SetMarked(true); + ActiveLocalDevice = lDevice; + } + fLocalDevicesMenu->AddItem(item); } } } + +void +BluetoothSettingsView::_MarkLocalDevice(LocalDevice* lDevice) +{ + // TODO: Device integrity should be rechecked. + + fExtDeviceView->SetLocalDevice(lDevice); + fExtDeviceView->SetEnabled(true); + ActiveLocalDevice = lDevice; + fSettings.Data.PickedDevice = lDevice->GetBluetoothAddress(); +} diff --git a/src/preferences/bluetooth/BluetoothSettingsView.h b/src/preferences/bluetooth/BluetoothSettingsView.h index d46bd1666c..25a03e439c 100644 --- a/src/preferences/bluetooth/BluetoothSettingsView.h +++ b/src/preferences/bluetooth/BluetoothSettingsView.h @@ -1,49 +1,58 @@ /* - * Copyright 2008-09, Oliver Ruiz Dorantes, + * Copyright 2008-2009, Oliver Ruiz Dorantes, + * Copyright 2012-2013, Tri-Edge AI, + * * All rights reserved. Distributed under the terms of the MIT License. */ + #ifndef BLUETOOTH_SETTINGS_VIEW_H #define BLUETOOTH_SETTINGS_VIEW_H +#include "BluetoothSettings.h" #include +class BluetoothSettings; +class ExtendedLocalDeviceView; +class LocalDevice; + class BBox; class BMenuField; class BPopUpMenu; class BSlider; -class ExtendedLocalDeviceView; - class BluetoothSettingsView : public BView { public: - BluetoothSettingsView(const char* name); - virtual ~BluetoothSettingsView(); + BluetoothSettingsView(const char* name); + virtual ~BluetoothSettingsView(); - virtual void AttachedToWindow(); - virtual void MessageReceived(BMessage* message); + virtual void AttachedToWindow(); + virtual void MessageReceived(BMessage* message); private: - void _BuildConnectionPolicy(); - void _BuildClassMenu(); - void _BuildLocalDevicesMenu(); - bool _SetDeviceClass(uint8 major, uint8 minor - , uint16 service); + void _BuildConnectionPolicy(); + void _BuildClassMenu(); + void _BuildLocalDevicesMenu(); + bool _SetDeviceClass(uint8 major, uint8 minor, + uint16 service); + void _MarkLocalDevice(LocalDevice* lDevice); protected: - float fDivider; + BluetoothSettings fSettings; - BMenuField* fPolicyMenuField; - BPopUpMenu* fPolicyMenu; - BMenuField* fClassMenuField; - BPopUpMenu* fClassMenu; - BMenuField* fLocalDevicesMenuField; - BPopUpMenu* fLocalDevicesMenu; + float fDivider; - ExtendedLocalDeviceView* fExtDeviceView; + BMenuField* fPolicyMenuField; + BPopUpMenu* fPolicyMenu; + BMenuField* fClassMenuField; + BPopUpMenu* fClassMenu; + BMenuField* fLocalDevicesMenuField; + BPopUpMenu* fLocalDevicesMenu; - BSlider* fInquiryTimeControl; + ExtendedLocalDeviceView* fExtDeviceView; + + BSlider* fInquiryTimeControl; }; diff --git a/src/preferences/bluetooth/BluetoothWindow.cpp b/src/preferences/bluetooth/BluetoothWindow.cpp index 87c1938222..28cdf3568f 100644 --- a/src/preferences/bluetooth/BluetoothWindow.cpp +++ b/src/preferences/bluetooth/BluetoothWindow.cpp @@ -89,7 +89,6 @@ BluetoothWindow::BluetoothWindow(BRect frame) // tabView->AddTab(fConnChan); tabView->AddTab(fSettingsView); - fRevertButton->SetEnabled(false); AddChild(BGroupLayoutBuilder(B_VERTICAL, 0) diff --git a/src/preferences/bluetooth/BluetoothWindow.h b/src/preferences/bluetooth/BluetoothWindow.h index 24e299a60d..aef9f05cbe 100644 --- a/src/preferences/bluetooth/BluetoothWindow.h +++ b/src/preferences/bluetooth/BluetoothWindow.h @@ -2,37 +2,36 @@ * Copyright 2008-09, Oliver Ruiz Dorantes, * All rights reserved. Distributed under the terms of the MIT License. */ + #ifndef BLUETOOTH_WINDOW_H #define BLUETOOTH_WINDOW_H +#include "BluetoothSettingsView.h" + #include #include #include #include #include - -#include "BluetoothSettingsView.h" - +class BluetoothSettingsView; class RemoteDevicesView; class ConnChanView; -class BluetoothWindow : public BWindow -{ +class BluetoothWindow : public BWindow { public: - BluetoothWindow(BRect frame); + BluetoothWindow(BRect frame); bool QuitRequested(void); void MessageReceived(BMessage *message); - + private: - RemoteDevicesView* fRemoteDevices; - ConnChanView* fConnChan; - BButton* fDefaultsButton; - BButton* fRevertButton; - BMenuBar* fMenubar; - - BluetoothSettingsView* fSettingsView; + RemoteDevicesView* fRemoteDevices; + ConnChanView* fConnChan; + BButton* fDefaultsButton; + BButton* fRevertButton; + BMenuBar* fMenubar; + BluetoothSettingsView* fSettingsView; }; #endif diff --git a/src/preferences/bluetooth/ExtendedLocalDeviceView.cpp b/src/preferences/bluetooth/ExtendedLocalDeviceView.cpp index 575c044ea2..31ddfaff28 100644 --- a/src/preferences/bluetooth/ExtendedLocalDeviceView.cpp +++ b/src/preferences/bluetooth/ExtendedLocalDeviceView.cpp @@ -72,7 +72,7 @@ ExtendedLocalDeviceView::SetLocalDevice(LocalDevice* lDevice) fDevice = lDevice; SetName(lDevice->GetFriendlyName().String()); fDeviceView->SetBluetoothDevice(lDevice); - + ClearDevice(); int value = fDevice->GetDiscoverable(); @@ -110,12 +110,12 @@ void ExtendedLocalDeviceView::MessageReceived(BMessage* message) { printf("ExtendedLocalDeviceView::MessageReceived\n"); - + if (fDevice == NULL) { printf("ExtendedLocalDeviceView::Device missing\n"); return; } - + if (message->WasDropped()) { } @@ -157,7 +157,7 @@ void ExtendedLocalDeviceView::SetEnabled(bool value) { printf("ExtendedLocalDeviceView::SetEnabled\n"); - + fVisible->SetEnabled(value); fAuthentication->SetEnabled(value); fDiscoverable->SetEnabled(value); @@ -168,7 +168,7 @@ void ExtendedLocalDeviceView::ClearDevice() { printf("ExtendedLocalDeviceView::ClearDevice\n"); - + fVisible->SetValue(false); fAuthentication->SetValue(false); fDiscoverable->SetValue(false); diff --git a/src/preferences/bluetooth/Jamfile b/src/preferences/bluetooth/Jamfile index 4b620f51db..351cab064f 100644 --- a/src/preferences/bluetooth/Jamfile +++ b/src/preferences/bluetooth/Jamfile @@ -8,6 +8,7 @@ AddResources Bluetooth : bluetooth-pref.rdef ; Preference Bluetooth : BluetoothDeviceView.cpp BluetoothMain.cpp + BluetoothSettings.cpp BluetoothSettingsView.cpp BluetoothWindow.cpp DeviceListItem.cpp diff --git a/src/preferences/time/ClockView.cpp b/src/preferences/time/ClockView.cpp index 8c51c675a1..82085c9f33 100644 --- a/src/preferences/time/ClockView.cpp +++ b/src/preferences/time/ClockView.cpp @@ -6,6 +6,7 @@ * John Scipione */ + #include "ClockView.h" #include @@ -24,9 +25,8 @@ #include "TimeMessages.h" -static const char* kDeskbarSignature = "application/x-vnd.Be-TSKB"; - -static const float kIndentSpacing +static const char* kDeskbarSignature = "application/x-vnd.Be-TSKB"; +static const float kIndentSpacing = be_control_look->DefaultItemSpacing() * 2.3; diff --git a/src/preferences/time/Jamfile b/src/preferences/time/Jamfile index c0579a753f..bd1295a37b 100644 --- a/src/preferences/time/Jamfile +++ b/src/preferences/time/Jamfile @@ -19,6 +19,7 @@ local sources = TimeSettings.cpp TimeWindow.cpp TimeZoneListItem.cpp + TimeZoneListView.cpp TZDisplay.cpp ZoneView.cpp ; @@ -44,5 +45,6 @@ DoCatalogs Time : ntp.cpp Time.cpp TimeWindow.cpp + TimeZoneListView.cpp ZoneView.cpp ; diff --git a/src/preferences/time/TimeZoneListView.cpp b/src/preferences/time/TimeZoneListView.cpp new file mode 100644 index 0000000000..84598c6993 --- /dev/null +++ b/src/preferences/time/TimeZoneListView.cpp @@ -0,0 +1,67 @@ +/* + * Copyright 2012, Haiku Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Sean Bailey +*/ + + +#include "TimeZoneListView.h" + +#include + +#include +#include +#include +#include +#include + +#include "TimeZoneListItem.h" + + +#undef B_TRANSLATION_CONTEXT +#define B_TRANSLATION_CONTEXT "Time" + + +TimeZoneListView::TimeZoneListView(void) + : + BOutlineListView("cityList", B_SINGLE_SELECTION_LIST) +{ +} + + +TimeZoneListView::~TimeZoneListView() +{ +} + + +bool +TimeZoneListView::GetToolTipAt(BPoint point, BToolTip** _tip) +{ + TimeZoneListItem* item = static_cast( + this->ItemAt(this->IndexOf(point))); + if (item == NULL || !item->HasTimeZone()) + return false; + + BString nowInTimeZone; + time_t now = time(NULL); + BLocale::Default()->FormatTime(&nowInTimeZone, now, B_SHORT_TIME_FORMAT, + &item->TimeZone()); + + BString dateInTimeZone; + BLocale::Default()->FormatDate(&dateInTimeZone, now, B_SHORT_DATE_FORMAT, + &item->TimeZone()); + + BString toolTip = item->Text(); + toolTip << '\n' << item->TimeZone().ShortName() << " / " + << item->TimeZone().ShortDaylightSavingName() + << B_TRANSLATE("\nNow: ") << nowInTimeZone + << " (" << dateInTimeZone << ')'; + + SetToolTip(toolTip.String()); + + *_tip = ToolTip(); + + return true; +} diff --git a/src/preferences/time/TimeZoneListView.h b/src/preferences/time/TimeZoneListView.h new file mode 100644 index 0000000000..7814e844aa --- /dev/null +++ b/src/preferences/time/TimeZoneListView.h @@ -0,0 +1,25 @@ +/* + * Copyright 2012, Haiku Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Sean Bailey + */ +#ifndef _TIME_ZONE_LIST_VIEW_H +#define _TIME_ZONE_LIST_VIEW_H + + +#include + + +class TimeZoneListView : public BOutlineListView { +public: + TimeZoneListView(void); + ~TimeZoneListView(); + +protected: + virtual bool GetToolTipAt(BPoint point, BToolTip** _tip); +}; + + +#endif // _TIME_ZONE_LIST_VIEW_H diff --git a/src/preferences/time/ZoneView.cpp b/src/preferences/time/ZoneView.cpp index c773de5645..08f53327db 100644 --- a/src/preferences/time/ZoneView.cpp +++ b/src/preferences/time/ZoneView.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2004-2010, Haiku, Inc. All Rights Reserved. + * Copyright 2004-2012, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. * * Authors: @@ -42,7 +42,6 @@ #include #include #include -#include #include #include @@ -52,6 +51,7 @@ #include "TimeMessages.h" #include "TimeZoneListItem.h" +#include "TimeZoneListView.h" #include "TZDisplay.h" @@ -84,7 +84,6 @@ TimeZoneView::TimeZoneView(const char* name) : BGroupView(name, B_HORIZONTAL, B_USE_DEFAULT_SPACING), fGmtTime(NULL), - fToolTip(NULL), fUseGmtTime(false), fCurrentZoneItem(NULL), fOldZoneItem(NULL), @@ -107,8 +106,6 @@ TimeZoneView::CheckCanRevert() TimeZoneView::~TimeZoneView() { - if (fToolTip != NULL) - fToolTip->ReleaseReference(); _WriteRTCSettings(); } @@ -189,41 +186,6 @@ TimeZoneView::MessageReceived(BMessage* message) } -bool -TimeZoneView::GetToolTipAt(BPoint point, BToolTip** _tip) -{ - TimeZoneListItem* item = static_cast( - fZoneList->ItemAt(fZoneList->IndexOf(point))); - if (item == NULL || !item->HasTimeZone()) - return false; - - BString nowInTimeZone; - time_t now = time(NULL); - BLocale::Default()->FormatTime(&nowInTimeZone, now, B_SHORT_TIME_FORMAT, - &item->TimeZone()); - - BString dateInTimeZone; - BLocale::Default()->FormatDate(&dateInTimeZone, now, B_SHORT_DATE_FORMAT, - &item->TimeZone()); - - BString toolTip = item->Text(); - toolTip << '\n' << item->TimeZone().ShortName() << " / " - << item->TimeZone().ShortDaylightSavingName() - << B_TRANSLATE("\nNow: ") << nowInTimeZone - << " (" << dateInTimeZone << ')'; - - if (fToolTip != NULL) - fToolTip->ReleaseReference(); - fToolTip = new (std::nothrow) BTextToolTip(toolTip.String()); - if (fToolTip == NULL) - return false; - - *_tip = fToolTip; - - return true; -} - - void TimeZoneView::_UpdateDateTime(BMessage* message) { @@ -243,7 +205,7 @@ TimeZoneView::_UpdateDateTime(BMessage* message) void TimeZoneView::_InitView() { - fZoneList = new BOutlineListView("cityList", B_SINGLE_SELECTION_LIST); + fZoneList = new TimeZoneListView(); fZoneList->SetSelectionMessage(new BMessage(H_CITY_CHANGED)); fZoneList->SetInvocationMessage(new BMessage(H_SET_TIME_ZONE)); _BuildZoneMenu(); diff --git a/src/preferences/time/ZoneView.h b/src/preferences/time/ZoneView.h index b0ac9b49b6..9766263709 100644 --- a/src/preferences/time/ZoneView.h +++ b/src/preferences/time/ZoneView.h @@ -1,5 +1,5 @@ /* - * Copyright 2004-2011, Haiku, Inc. All Rights Reserved. + * Copyright 2004-2012, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. * * Authors: @@ -20,9 +20,9 @@ class BMessage; class BOutlineListView; class BPopUpMenu; class BRadioButton; -class BTextToolTip; class BTimeZone; class TimeZoneListItem; +class TimeZoneListView; class TTZDisplay; @@ -36,7 +36,6 @@ public: bool CheckCanRevert(); protected: - virtual bool GetToolTipAt(BPoint point, BToolTip** _tip); virtual void DoLayout(); private: @@ -58,15 +57,13 @@ private: void _Revert(); - BOutlineListView* fZoneList; + TimeZoneListView* fZoneList; BButton* fSetZone; TTZDisplay* fCurrent; TTZDisplay* fPreview; BRadioButton* fLocalTime; BRadioButton* fGmtTime; - BTextToolTip* fToolTip; - int32 fLastUpdateMinute; bool fUseGmtTime; bool fOldUseGmtTime; diff --git a/src/servers/Jamfile b/src/servers/Jamfile index 141a8ad6ee..a2bc798595 100644 --- a/src/servers/Jamfile +++ b/src/servers/Jamfile @@ -6,6 +6,7 @@ SubInclude HAIKU_TOP src servers cddb_daemon ; SubInclude HAIKU_TOP src servers debug ; SubInclude HAIKU_TOP src servers index ; SubInclude HAIKU_TOP src servers input ; +SubInclude HAIKU_TOP src servers keystore ; SubInclude HAIKU_TOP src servers mail ; SubInclude HAIKU_TOP src servers media ; SubInclude HAIKU_TOP src servers media_addon ; diff --git a/src/servers/keystore/AppAccessRequestWindow.cpp b/src/servers/keystore/AppAccessRequestWindow.cpp new file mode 100644 index 0000000000..bb63438373 --- /dev/null +++ b/src/servers/keystore/AppAccessRequestWindow.cpp @@ -0,0 +1,227 @@ +/* + * Copyright 2012, Michael Lotz, mmlr@mlotz.ch. All Rights Reserved. + * Distributed under the terms of the MIT License. + */ + + +#include "AppAccessRequestWindow.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +static const uint32 kMessageDisallow = 'btda'; +static const uint32 kMessageOnce = 'btao'; +static const uint32 kMessageAlways = 'btaa'; + + +class AppAccessRequestView : public BView { +public: + AppAccessRequestView(const char* keyringName, const char* signature, + const char* path, const char* accessString, bool appIsNew, + bool appWasUpdated) + : + BView("AppAccessRequestView", B_WILL_DRAW) + { + SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + + BGroupLayout* rootLayout = new(std::nothrow) BGroupLayout(B_VERTICAL); + if (rootLayout == NULL) + return; + + SetLayout(rootLayout); + + float inset = ceilf(be_plain_font->Size() * 0.7); + rootLayout->SetInsets(inset, inset, inset, inset); + rootLayout->SetSpacing(inset); + + BTextView* message = new(std::nothrow) BTextView("Message"); + if (message == NULL) + return; + + BString details; + details << "The application:\n" + << signature << " (" << path << ")\n\n"; + + if (keyringName != NULL) { + details << "requests access to keyring:\n" + << keyringName << "\n\n"; + } + + if (accessString != NULL) { + details << "to perform the following action:\n" + << accessString << "\n\n"; + } + + if (appIsNew) + details << "This application hasn't been granted access before."; + else if (appWasUpdated) { + details << "This application has been updated since it was last" + << " granted access."; + } else { + details << "This application doesn't yet have the required" + " privileges."; + } + + message->SetText(details); + message->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + rgb_color textColor = ui_color(B_PANEL_TEXT_COLOR); + message->SetFontAndColor(be_plain_font, B_FONT_ALL, &textColor); + message->MakeEditable(false); + message->MakeSelectable(false); + message->SetWordWrap(true); + + message->SetExplicitMinSize(BSize(message->StringWidth( + "01234567890123456789012345678901234567890123456789") + inset, + B_SIZE_UNSET)); + + BGroupView* buttons = new(std::nothrow) BGroupView(B_HORIZONTAL); + if (buttons == NULL) + return; + + fDisallowButton = new(std::nothrow) BButton("Disallow", + new BMessage(kMessageDisallow)); + buttons->GroupLayout()->AddView(fDisallowButton); + + buttons->GroupLayout()->AddItem(BSpaceLayoutItem::CreateGlue()); + + fOnceButton = new(std::nothrow) BButton("Allow Once", + new BMessage(kMessageOnce)); + buttons->GroupLayout()->AddView(fOnceButton); + + fAlwaysButton = new(std::nothrow) BButton("Allow Always", + new BMessage(kMessageAlways)); + buttons->GroupLayout()->AddView(fAlwaysButton); + + rootLayout->AddView(message); + rootLayout->AddView(buttons); + } + + virtual void + AttachedToWindow() + { + fDisallowButton->SetTarget(Window()); + fOnceButton->SetTarget(Window()); + fAlwaysButton->SetTarget(Window()); + + // TODO: Decide for a sane default button (or none at all). + //fButton->MakeDefault(true); + } + +private: + BButton* fDisallowButton; + BButton* fOnceButton; + BButton* fAlwaysButton; +}; + + +AppAccessRequestWindow::AppAccessRequestWindow(const char* keyringName, + const char* signature, const char* path, const char* accessString, + bool appIsNew, bool appWasUpdated) + : + BWindow(BRect(50, 50, 269, 302), "Application Keyring Access", + B_TITLED_WINDOW, B_NOT_RESIZABLE | B_ASYNCHRONOUS_CONTROLS + | B_NOT_ZOOMABLE | B_AUTO_UPDATE_SIZE_LIMITS), + fRequestView(NULL), + fDoneSem(-1), + fResult(kMessageDisallow) +{ + fDoneSem = create_sem(0, "application keyring access dialog"); + if (fDoneSem < 0) + return; + + BLayout* layout = new(std::nothrow) BGroupLayout(B_HORIZONTAL); + if (layout == NULL) + return; + + SetLayout(layout); + + fRequestView = new(std::nothrow) AppAccessRequestView(keyringName, + signature, path, accessString, appIsNew, appWasUpdated); + if (fRequestView == NULL) + return; + + layout->AddView(fRequestView); +} + + +AppAccessRequestWindow::~AppAccessRequestWindow() +{ + if (fDoneSem >= 0) + delete_sem(fDoneSem); +} + + +void +AppAccessRequestWindow::DispatchMessage(BMessage* message, BHandler* handler) +{ + int8 key; + if (message->what == B_KEY_DOWN + && message->FindInt8("byte", 0, &key) == B_OK + && key == B_ESCAPE) { + PostMessage(kMessageDisallow); + } + + BWindow::DispatchMessage(message, handler); +} + + +void +AppAccessRequestWindow::MessageReceived(BMessage* message) +{ + switch (message->what) { + case kMessageDisallow: + case kMessageOnce: + case kMessageAlways: + fResult = message->what; + release_sem(fDoneSem); + return; + } + + BWindow::MessageReceived(message); +} + + +status_t +AppAccessRequestWindow::RequestAppAccess(bool& allowAlways) +{ + CenterOnScreen(); + Show(); + + while (acquire_sem(fDoneSem) == B_INTERRUPTED) + ; + + status_t result; + switch (fResult) { + default: + case kMessageDisallow: + result = B_NOT_ALLOWED; + allowAlways = false; + break; + case kMessageOnce: + result = B_OK; + allowAlways = false; + break; + case kMessageAlways: + result = B_OK; + allowAlways = true; + break; + } + + LockLooper(); + Quit(); + return result; +} diff --git a/src/servers/keystore/AppAccessRequestWindow.h b/src/servers/keystore/AppAccessRequestWindow.h new file mode 100644 index 0000000000..e8fbee8a5b --- /dev/null +++ b/src/servers/keystore/AppAccessRequestWindow.h @@ -0,0 +1,39 @@ +/* + * Copyright 2012, Michael Lotz, mmlr@mlotz.ch. All Rights Reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _APP_ACCESS_REQUEST_WINDOW_H +#define _APP_ACCESS_REQUEST_WINDOW_H + + +#include +#include + + +class AppAccessRequestView; + + +class AppAccessRequestWindow : public BWindow { +public: + AppAccessRequestWindow( + const char* keyringName, + const char* signature, + const char* path, + const char* accessString, bool appIsNew, + bool appWasUpdated); +virtual ~AppAccessRequestWindow(); + +virtual void DispatchMessage(BMessage* message, + BHandler* handler); +virtual void MessageReceived(BMessage* message); + + status_t RequestAppAccess(bool& allowAlways); + +private: + AppAccessRequestView* fRequestView; + sem_id fDoneSem; + uint32 fResult; +}; + + +#endif // _APP_ACCESS_REQUEST_WINDOW_H diff --git a/src/servers/keystore/Jamfile b/src/servers/keystore/Jamfile new file mode 100644 index 0000000000..b89085a58e --- /dev/null +++ b/src/servers/keystore/Jamfile @@ -0,0 +1,13 @@ +SubDir HAIKU_TOP src servers keystore ; + +UsePrivateHeaders app ; + +Server keystore_server : + AppAccessRequestWindow.cpp + KeyRequestWindow.cpp + Keyring.cpp + KeyStoreServer.cpp + + : be $(TARGET_LIBSTDC++) + : keystore_server.rdef +; diff --git a/src/servers/keystore/KeyRequestWindow.cpp b/src/servers/keystore/KeyRequestWindow.cpp new file mode 100644 index 0000000000..61c7111f1f --- /dev/null +++ b/src/servers/keystore/KeyRequestWindow.cpp @@ -0,0 +1,229 @@ +/* + * Copyright 2012, Michael Lotz, mmlr@mlotz.ch. All Rights Reserved. + * Distributed under the terms of the MIT License. + */ + + +#include "KeyRequestWindow.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +static const uint32 kMessageCancel = 'btcl'; +static const uint32 kMessageUnlock = 'btul'; + + +class KeyRequestView : public BView { +public: + KeyRequestView() + : + BView("KeyRequestView", B_WILL_DRAW), + fPassword(NULL) + { + SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + + BGroupLayout* rootLayout = new(std::nothrow) BGroupLayout(B_VERTICAL); + if (rootLayout == NULL) + return; + + SetLayout(rootLayout); + + BGridView* controls = new(std::nothrow) BGridView(); + if (controls == NULL) + return; + + BGridLayout* layout = controls->GridLayout(); + + float inset = ceilf(be_plain_font->Size() * 0.7); + rootLayout->SetInsets(inset, inset, inset, inset); + rootLayout->SetSpacing(inset); + layout->SetSpacing(inset, inset); + + BStringView* label = new(std::nothrow) BStringView("keyringLabel", + "Keyring:"); + if (label == NULL) + return; + + int32 row = 0; + layout->AddView(label, 0, row); + + fKeyringName = new(std::nothrow) BStringView("keyringName", ""); + if (fKeyringName == NULL) + return; + + layout->AddView(fKeyringName, 1, row++); + + fPassword = new(std::nothrow) BTextControl("Password:", "", NULL); + if (fPassword == NULL) + return; + + BLayoutItem* layoutItem = fPassword->CreateTextViewLayoutItem(); + layoutItem->SetExplicitMinSize(BSize(fPassword->StringWidth( + "0123456789012345678901234567890123456789") + inset, + B_SIZE_UNSET)); + + layout->AddItem(fPassword->CreateLabelLayoutItem(), 0, row); + layout->AddItem(layoutItem, 1, row++); + + BGroupView* buttons = new(std::nothrow) BGroupView(B_HORIZONTAL); + if (buttons == NULL) + return; + + fCancelButton = new(std::nothrow) BButton("Cancel", + new BMessage(kMessageCancel)); + buttons->GroupLayout()->AddView(fCancelButton); + + buttons->GroupLayout()->AddItem(BSpaceLayoutItem::CreateGlue()); + + fUnlockButton = new(std::nothrow) BButton("Unlock", + new BMessage(kMessageUnlock)); + buttons->GroupLayout()->AddView(fUnlockButton); + + BTextView* message = new(std::nothrow) BTextView("message"); + message->SetText("An application wants to access the keyring below, " + "but it is locked with a passphrase. Please enter the passphrase " + "to unlock the keyring.\n" + "If you unlock the keyring, it stays unlocked until the system is " + "shut down or the keyring is manually locked again.\n" + "If you cancel this dialog the keyring will remain locked."); + message->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + rgb_color textColor = ui_color(B_PANEL_TEXT_COLOR); + message->SetFontAndColor(be_plain_font, B_FONT_ALL, &textColor); + message->MakeEditable(false); + message->MakeSelectable(false); + message->SetWordWrap(true); + + rootLayout->AddView(message); + rootLayout->AddView(controls); + rootLayout->AddView(buttons); + } + + virtual void + AttachedToWindow() + { + fCancelButton->SetTarget(Window()); + fUnlockButton->SetTarget(Window()); + fUnlockButton->MakeDefault(true); + fPassword->MakeFocus(); + } + + void + SetUp(const BString& keyringName) + { + fKeyringName->SetText(keyringName); + } + + status_t + Complete(BMessage& keyMessage) + { + BPasswordKey password(fPassword->Text(), B_KEY_PURPOSE_KEYRING, ""); + return password.Flatten(keyMessage); + } + +private: + BStringView* fKeyringName; + BTextControl* fPassword; + BButton* fCancelButton; + BButton* fUnlockButton; +}; + + +KeyRequestWindow::KeyRequestWindow() + : + BWindow(BRect(50, 50, 269, 302), "Unlock Keyring", + B_TITLED_WINDOW, B_NOT_RESIZABLE | B_ASYNCHRONOUS_CONTROLS + | B_NOT_ZOOMABLE | B_AUTO_UPDATE_SIZE_LIMITS), + fRequestView(NULL), + fDoneSem(-1), + fResult(B_ERROR) +{ + fDoneSem = create_sem(0, "keyring unlock dialog"); + if (fDoneSem < 0) + return; + + BLayout* layout = new(std::nothrow) BGroupLayout(B_HORIZONTAL); + if (layout == NULL) + return; + + SetLayout(layout); + + fRequestView = new(std::nothrow) KeyRequestView(); + if (fRequestView == NULL) + return; + + layout->AddView(fRequestView); +} + + +KeyRequestWindow::~KeyRequestWindow() +{ + if (fDoneSem >= 0) + delete_sem(fDoneSem); +} + + +void +KeyRequestWindow::DispatchMessage(BMessage* message, BHandler* handler) +{ + int8 key; + if (message->what == B_KEY_DOWN + && message->FindInt8("byte", 0, &key) == B_OK + && key == B_ESCAPE) { + PostMessage(kMessageCancel); + } + + BWindow::DispatchMessage(message, handler); +} + + +void +KeyRequestWindow::MessageReceived(BMessage* message) +{ + switch (message->what) { + case kMessageCancel: + case kMessageUnlock: + fResult = message->what == kMessageUnlock ? B_OK : B_CANCELED; + release_sem(fDoneSem); + return; + } + + BWindow::MessageReceived(message); +} + + +status_t +KeyRequestWindow::RequestKey(const BString& keyringName, BMessage& keyMessage) +{ + fRequestView->SetUp(keyringName); + + CenterOnScreen(); + Show(); + + while (acquire_sem(fDoneSem) == B_INTERRUPTED) + ; + + status_t result = fResult; + if (result == B_OK) + result = fRequestView->Complete(keyMessage); + + LockLooper(); + Quit(); + return result; +} diff --git a/src/servers/keystore/KeyRequestWindow.h b/src/servers/keystore/KeyRequestWindow.h new file mode 100644 index 0000000000..8c535d6e78 --- /dev/null +++ b/src/servers/keystore/KeyRequestWindow.h @@ -0,0 +1,35 @@ +/* + * Copyright 2012, Michael Lotz, mmlr@mlotz.ch. All Rights Reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _KEY_REQUEST_WINDOW_H +#define _KEY_REQUEST_WINDOW_H + + +#include +#include + + +class KeyRequestView; + + +class KeyRequestWindow : public BWindow { +public: + KeyRequestWindow(); +virtual ~KeyRequestWindow(); + +virtual void DispatchMessage(BMessage* message, + BHandler* handler); +virtual void MessageReceived(BMessage* message); + + status_t RequestKey(const BString& keyringName, + BMessage& keyMessage); + +private: + KeyRequestView* fRequestView; + sem_id fDoneSem; + status_t fResult; +}; + + +#endif // _KEY_REQUEST_WINDOW_H diff --git a/src/servers/keystore/KeyStoreServer.cpp b/src/servers/keystore/KeyStoreServer.cpp new file mode 100644 index 0000000000..1c7ca387a6 --- /dev/null +++ b/src/servers/keystore/KeyStoreServer.cpp @@ -0,0 +1,800 @@ +/* + * Copyright 2012, Michael Lotz, mmlr@mlotz.ch. All Rights Reserved. + * Distributed under the terms of the MIT License. + */ + + +#include "KeyStoreServer.h" + +#include "AppAccessRequestWindow.h" +#include "KeyRequestWindow.h" +#include "Keyring.h" + +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include + + +using namespace BPrivate; + + +static const char* kMasterKeyringName = "Master"; +static const char* kKeyringKeysIdentifier = "Keyrings"; + +static const uint32 kKeyStoreFormatVersion = 1; + +static const uint32 kFlagGetKey = 0x0001; +static const uint32 kFlagEnumerateKeys = 0x0002; +static const uint32 kFlagAddKey = 0x0004; +static const uint32 kFlagRemoveKey = 0x0008; +static const uint32 kFlagAddKeyring = 0x0010; +static const uint32 kFlagRemoveKeyring = 0x0020; +static const uint32 kFlagEnumerateKeyrings = 0x0040; +static const uint32 kFlagSetUnlockKey = 0x0080; +static const uint32 kFlagRemoveUnlockKey = 0x0100; +static const uint32 kFlagAddKeyringsToMaster = 0x0200; +static const uint32 kFlagRemoveKeyringsFromMaster = 0x0400; +static const uint32 kFlagEnumerateMasterKeyrings = 0x0800; +static const uint32 kFlagQueryLockState = 0x1000; +static const uint32 kFlagLockKeyring = 0x2000; +static const uint32 kFlagEnumerateApplications = 0x4000; +static const uint32 kFlagRemoveApplications = 0x8000; + +static const uint32 kDefaultAppFlags = kFlagGetKey | kFlagEnumerateKeys + | kFlagAddKey | kFlagRemoveKey | kFlagAddKeyring | kFlagRemoveKeyring + | kFlagEnumerateKeyrings | kFlagSetUnlockKey | kFlagRemoveUnlockKey + | kFlagAddKeyringsToMaster | kFlagRemoveKeyringsFromMaster + | kFlagEnumerateMasterKeyrings | kFlagQueryLockState | kFlagLockKeyring + | kFlagEnumerateApplications | kFlagRemoveApplications; + + +KeyStoreServer::KeyStoreServer() + : + BApplication(kKeyStoreServerSignature), + fMasterKeyring(NULL), + fKeyrings(20, true) +{ + BPath path; + if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK) + return; + + BDirectory settingsDir(path.Path()); + path.Append("system"); + if (!settingsDir.Contains(path.Path())) + settingsDir.CreateDirectory(path.Path(), NULL); + + settingsDir.SetTo(path.Path()); + path.Append("keystore"); + if (!settingsDir.Contains(path.Path())) + settingsDir.CreateDirectory(path.Path(), NULL); + + settingsDir.SetTo(path.Path()); + path.Append("keystore_database"); + + fKeyStoreFile.SetTo(path.Path(), B_READ_WRITE + | (settingsDir.Contains(path.Path()) ? 0 : B_CREATE_FILE)); + + _ReadKeyStoreDatabase(); + + if (fMasterKeyring == NULL) { + fMasterKeyring = new(std::nothrow) Keyring(kMasterKeyringName); + fKeyrings.BinaryInsert(fMasterKeyring, &Keyring::Compare); + } +} + + +KeyStoreServer::~KeyStoreServer() +{ +} + + +void +KeyStoreServer::MessageReceived(BMessage* message) +{ + BMessage reply; + status_t result = B_UNSUPPORTED; + app_info callingAppInfo; + + uint32 accessFlags = _AccessFlagsFor(message->what); + if (accessFlags == 0) + message->what = 0; + + if (message->what != 0) { + result = _ResolveCallingApp(*message, callingAppInfo); + if (result != B_OK) + message->what = 0; + } + + // Resolve the keyring for the relevant messages. + Keyring* keyring = NULL; + switch (message->what) { + case KEY_STORE_GET_KEY: + case KEY_STORE_GET_NEXT_KEY: + case KEY_STORE_ADD_KEY: + case KEY_STORE_REMOVE_KEY: + case KEY_STORE_IS_KEYRING_UNLOCKED: + case KEY_STORE_LOCK_KEYRING: + case KEY_STORE_SET_UNLOCK_KEY: + case KEY_STORE_REMOVE_UNLOCK_KEY: + case KEY_STORE_ADD_KEYRING_TO_MASTER: + case KEY_STORE_REMOVE_KEYRING_FROM_MASTER: + case KEY_STORE_GET_NEXT_APPLICATION: + case KEY_STORE_REMOVE_APPLICATION: + { + BString keyringName; + if (message->FindString("keyring", &keyringName) != B_OK) + keyringName = ""; + + keyring = _FindKeyring(keyringName); + if (keyring == NULL) { + result = B_BAD_VALUE; + message->what = 0; + // So that we don't do anything in the second switch. + break; + } + + switch (message->what) { + case KEY_STORE_GET_KEY: + case KEY_STORE_GET_NEXT_KEY: + case KEY_STORE_ADD_KEY: + case KEY_STORE_REMOVE_KEY: + case KEY_STORE_SET_UNLOCK_KEY: + case KEY_STORE_REMOVE_UNLOCK_KEY: + case KEY_STORE_ADD_KEYRING_TO_MASTER: + case KEY_STORE_GET_NEXT_APPLICATION: + case KEY_STORE_REMOVE_APPLICATION: + { + // These need keyring access to do anything. + while (!keyring->IsUnlocked()) { + status_t unlockResult = _UnlockKeyring(*keyring); + if (unlockResult != B_OK) { + result = unlockResult; + message->what = 0; + break; + } + } + + status_t validateResult = _ValidateAppAccess(*keyring, + callingAppInfo, accessFlags); + if (validateResult != B_OK) { + result = validateResult; + message->what = 0; + break; + } + + break; + } + } + + break; + } + } + + switch (message->what) { + case KEY_STORE_GET_KEY: + { + BString identifier; + if (message->FindString("identifier", &identifier) != B_OK) { + result = B_BAD_VALUE; + break; + } + + bool secondaryIdentifierOptional; + if (message->FindBool("secondaryIdentifierOptional", + &secondaryIdentifierOptional) != B_OK) { + secondaryIdentifierOptional = false; + } + + BString secondaryIdentifier; + if (message->FindString("secondaryIdentifier", + &secondaryIdentifier) != B_OK) { + secondaryIdentifier = ""; + secondaryIdentifierOptional = true; + } + + BMessage keyMessage; + result = keyring->FindKey(identifier, secondaryIdentifier, + secondaryIdentifierOptional, &keyMessage); + if (result == B_OK) + reply.AddMessage("key", &keyMessage); + + break; + } + + case KEY_STORE_GET_NEXT_KEY: + { + BKeyType type; + BKeyPurpose purpose; + uint32 cookie; + if (message->FindUInt32("type", (uint32*)&type) != B_OK + || message->FindUInt32("purpose", (uint32*)&purpose) != B_OK + || message->FindUInt32("cookie", &cookie) != B_OK) { + result = B_BAD_VALUE; + break; + } + + BMessage keyMessage; + result = keyring->FindKey(type, purpose, cookie, keyMessage); + if (result == B_OK) { + cookie++; + reply.AddUInt32("cookie", cookie); + reply.AddMessage("key", &keyMessage); + } + + break; + } + + case KEY_STORE_ADD_KEY: + { + BMessage keyMessage; + BString identifier; + if (message->FindMessage("key", &keyMessage) != B_OK + || keyMessage.FindString("identifier", &identifier) != B_OK) { + result = B_BAD_VALUE; + break; + } + + BString secondaryIdentifier; + if (keyMessage.FindString("secondaryIdentifier", + &secondaryIdentifier) != B_OK) { + secondaryIdentifier = ""; + } + + result = keyring->AddKey(identifier, secondaryIdentifier, keyMessage); + if (result == B_OK) + _WriteKeyStoreDatabase(); + + break; + } + + case KEY_STORE_REMOVE_KEY: + { + BMessage keyMessage; + BString identifier; + if (message->FindMessage("key", &keyMessage) != B_OK + || keyMessage.FindString("identifier", &identifier) != B_OK) { + result = B_BAD_VALUE; + break; + } + + result = keyring->RemoveKey(identifier, keyMessage); + if (result == B_OK) + _WriteKeyStoreDatabase(); + + break; + } + + case KEY_STORE_ADD_KEYRING: + { + BMessage keyMessage; + BString keyring; + if (message->FindString("keyring", &keyring) != B_OK) { + result = B_BAD_VALUE; + break; + } + + result = _AddKeyring(keyring); + if (result == B_OK) + _WriteKeyStoreDatabase(); + + break; + } + + case KEY_STORE_REMOVE_KEYRING: + { + BString keyringName; + if (message->FindString("keyring", &keyringName) != B_OK) + keyringName = ""; + + result = _RemoveKeyring(keyringName); + if (result == B_OK) + _WriteKeyStoreDatabase(); + + break; + } + + case KEY_STORE_GET_NEXT_KEYRING: + { + uint32 cookie; + if (message->FindUInt32("cookie", &cookie) != B_OK) { + result = B_BAD_VALUE; + break; + } + + keyring = fKeyrings.ItemAt(cookie); + if (keyring == NULL) { + result = B_ENTRY_NOT_FOUND; + break; + } + + cookie++; + reply.AddUInt32("cookie", cookie); + reply.AddString("keyring", keyring->Name()); + result = B_OK; + break; + } + + case KEY_STORE_IS_KEYRING_UNLOCKED: + { + reply.AddBool("unlocked", keyring->IsUnlocked()); + result = B_OK; + break; + } + + case KEY_STORE_LOCK_KEYRING: + { + keyring->Lock(); + result = B_OK; + break; + } + + case KEY_STORE_SET_UNLOCK_KEY: + { + BMessage keyMessage; + if (message->FindMessage("key", &keyMessage) != B_OK) { + result = B_BAD_VALUE; + break; + } + + result = keyring->SetUnlockKey(keyMessage); + if (result == B_OK) + _WriteKeyStoreDatabase(); + + // TODO: Update the key in the master if this keyring was added. + break; + } + + case KEY_STORE_REMOVE_UNLOCK_KEY: + { + result = keyring->RemoveUnlockKey(); + if (result == B_OK) + _WriteKeyStoreDatabase(); + + break; + } + + case KEY_STORE_ADD_KEYRING_TO_MASTER: + case KEY_STORE_REMOVE_KEYRING_FROM_MASTER: + { + // We also need access to the master keyring. + while (!fMasterKeyring->IsUnlocked()) { + status_t unlockResult = _UnlockKeyring(*fMasterKeyring); + if (unlockResult != B_OK) { + result = unlockResult; + message->what = 0; + break; + } + } + + if (message->what == 0) + break; + + BString secondaryIdentifier = keyring->Name(); + BMessage keyMessage = keyring->UnlockKey(); + keyMessage.RemoveName("identifier"); + keyMessage.AddString("identifier", kKeyringKeysIdentifier); + keyMessage.RemoveName("secondaryIdentifier"); + keyMessage.AddString("secondaryIdentifier", secondaryIdentifier); + + switch (message->what) { + case KEY_STORE_ADD_KEYRING_TO_MASTER: + result = fMasterKeyring->AddKey(kKeyringKeysIdentifier, + secondaryIdentifier, keyMessage); + break; + + case KEY_STORE_REMOVE_KEYRING_FROM_MASTER: + result = fMasterKeyring->RemoveKey(kKeyringKeysIdentifier, + keyMessage); + break; + } + + if (result == B_OK) + _WriteKeyStoreDatabase(); + + break; + } + + case KEY_STORE_GET_NEXT_APPLICATION: + { + uint32 cookie; + if (message->FindUInt32("cookie", &cookie) != B_OK) { + result = B_BAD_VALUE; + break; + } + + BString signature; + BString path; + result = keyring->GetNextApplication(cookie, signature, path); + if (result != B_OK) + break; + + reply.AddUInt32("cookie", cookie); + reply.AddString("signature", signature); + reply.AddString("path", path); + result = B_OK; + break; + } + + case KEY_STORE_REMOVE_APPLICATION: + { + const char* signature = NULL; + const char* path = NULL; + + if (message->FindString("signature", &signature) != B_OK) { + result = B_BAD_VALUE; + break; + } + + if (message->FindString("path", &path) != B_OK) + path = NULL; + + result = keyring->RemoveApplication(signature, path); + if (result == B_OK) + _WriteKeyStoreDatabase(); + + break; + } + + case 0: + { + // Just the error case from above. + break; + } + + default: + { + printf("unknown message received: %" B_PRIu32 " \"%.4s\"\n", + message->what, (const char*)&message->what); + break; + } + } + + if (message->IsSourceWaiting()) { + if (result == B_OK) + reply.what = KEY_STORE_SUCCESS; + else { + reply.what = KEY_STORE_RESULT; + reply.AddInt32("result", result); + } + + message->SendReply(&reply); + } +} + + +status_t +KeyStoreServer::_ReadKeyStoreDatabase() +{ + BMessage keystore; + status_t result = keystore.Unflatten(&fKeyStoreFile); + if (result != B_OK) { + printf("failed to read keystore database\n"); + _WriteKeyStoreDatabase(); + // Reinitializes the database. + return result; + } + + int32 index = 0; + BMessage keyringData; + while (keystore.FindMessage("keyrings", index++, &keyringData) == B_OK) { + Keyring* keyring = new(std::nothrow) Keyring(); + if (keyring == NULL) { + printf("no memory for allocating keyring\n"); + break; + } + + status_t result = keyring->ReadFromMessage(keyringData); + if (result != B_OK) { + printf("failed to read keyring from data\n"); + delete keyring; + continue; + } + + if (strcmp(keyring->Name(), kMasterKeyringName) == 0) + fMasterKeyring = keyring; + + fKeyrings.BinaryInsert(keyring, &Keyring::Compare); + } + + return B_OK; +} + + +status_t +KeyStoreServer::_WriteKeyStoreDatabase() +{ + BMessage keystore; + keystore.AddUInt32("format", kKeyStoreFormatVersion); + + for (int32 i = 0; i < fKeyrings.CountItems(); i++) { + Keyring* keyring = fKeyrings.ItemAt(i); + if (keyring == NULL) + continue; + + BMessage keyringData; + status_t result = keyring->WriteToMessage(keyringData); + if (result != B_OK) + return result; + + keystore.AddMessage("keyrings", &keyringData); + } + + fKeyStoreFile.SetSize(0); + fKeyStoreFile.Seek(0, SEEK_SET); + return keystore.Flatten(&fKeyStoreFile); +} + + +uint32 +KeyStoreServer::_AccessFlagsFor(uint32 command) const +{ + switch (command) { + case KEY_STORE_GET_KEY: + return kFlagGetKey; + case KEY_STORE_GET_NEXT_KEY: + return kFlagEnumerateKeys; + case KEY_STORE_ADD_KEY: + return kFlagAddKey; + case KEY_STORE_REMOVE_KEY: + return kFlagRemoveKey; + case KEY_STORE_ADD_KEYRING: + return kFlagAddKeyring; + case KEY_STORE_REMOVE_KEYRING: + return kFlagRemoveKeyring; + case KEY_STORE_GET_NEXT_KEYRING: + return kFlagEnumerateKeyrings; + case KEY_STORE_SET_UNLOCK_KEY: + return kFlagSetUnlockKey; + case KEY_STORE_REMOVE_UNLOCK_KEY: + return kFlagRemoveUnlockKey; + case KEY_STORE_ADD_KEYRING_TO_MASTER: + return kFlagAddKeyringsToMaster; + case KEY_STORE_REMOVE_KEYRING_FROM_MASTER: + return kFlagRemoveKeyringsFromMaster; + case KEY_STORE_GET_NEXT_MASTER_KEYRING: + return kFlagEnumerateMasterKeyrings; + case KEY_STORE_IS_KEYRING_UNLOCKED: + return kFlagQueryLockState; + case KEY_STORE_LOCK_KEYRING: + return kFlagLockKeyring; + case KEY_STORE_GET_NEXT_APPLICATION: + return kFlagEnumerateApplications; + case KEY_STORE_REMOVE_APPLICATION: + return kFlagRemoveApplications; + } + + return 0; +} + + +const char* +KeyStoreServer::_AccessStringFor(uint32 accessFlag) const +{ + switch (accessFlag) { + case kFlagGetKey: + return "Get keys from the keyring."; + case kFlagEnumerateKeys: + return "Enumerate and get keys from the keyring."; + case kFlagAddKey: + return "Add keys to the keyring."; + case kFlagRemoveKey: + return "Remove keys from the keyring."; + case kFlagAddKeyring: + return "Add new keyrings."; + case kFlagRemoveKeyring: + return "Remove keyrings."; + case kFlagEnumerateKeyrings: + return "Enumerate the available keyrings."; + case kFlagSetUnlockKey: + return "Set the unlock key of the keyring."; + case kFlagRemoveUnlockKey: + return "Remove the unlock key of the keyring."; + case kFlagAddKeyringsToMaster: + return "Add the keyring key to the master keyring."; + case kFlagRemoveKeyringsFromMaster: + return "Remove the keyring key from the master keyring."; + case kFlagEnumerateMasterKeyrings: + return "Enumerate keyrings added to the master keyring."; + case kFlagQueryLockState: + return "Query the lock state of the keyring."; + case kFlagLockKeyring: + return "Lock the keyring."; + case kFlagEnumerateApplications: + return "Enumerate the applications of the keyring."; + case kFlagRemoveApplications: + return "Remove applications from the keyring."; + } + + return NULL; +} + + +status_t +KeyStoreServer::_ResolveCallingApp(const BMessage& message, + app_info& callingAppInfo) const +{ + team_id callingTeam = message.ReturnAddress().Team(); + status_t result = be_roster->GetRunningAppInfo(callingTeam, + &callingAppInfo); + if (result != B_OK) + return result; + + // Do some sanity checks. + if (callingAppInfo.team != callingTeam) + return B_ERROR; + + return B_OK; +} + + +status_t +KeyStoreServer::_ValidateAppAccess(Keyring& keyring, const app_info& appInfo, + uint32 accessFlags) +{ + BMessage appMessage; + BPath path(&appInfo.ref); + status_t result = keyring.FindApplication(appInfo.signature, + path.Path(), appMessage); + if (result != B_OK && result != B_ENTRY_NOT_FOUND) + return result; + + // TODO: Implement running image checksum mechanism. + BString checksum = "dummy"; + + bool appIsNew = false; + bool appWasUpdated = false; + uint32 appFlags = 0; + BString appSum = ""; + if (result == B_OK) { + if (appMessage.FindUInt32("flags", &appFlags) != B_OK + || appMessage.FindString("checksum", &appSum) != B_OK) { + appIsNew = true; + appFlags = 0; + } else if (appSum != checksum) { + appWasUpdated = true; + appFlags = 0; + } + } else + appIsNew = true; + + if ((accessFlags & appFlags) == accessFlags) + return B_OK; + + const char* accessString = _AccessStringFor(accessFlags); + bool allowAlways = false; + result = _RequestAppAccess(keyring.Name(), appInfo.signature, path.Path(), + accessString, appIsNew, appWasUpdated, accessFlags, allowAlways); + if (result != B_OK || !allowAlways) + return result; + + appMessage.MakeEmpty(); + appMessage.AddString("path", path.Path()); + appMessage.AddUInt32("flags", appFlags | accessFlags); + appMessage.AddString("checksum", checksum); + + keyring.RemoveApplication(appInfo.signature, path.Path()); + if (keyring.AddApplication(appInfo.signature, appMessage) == B_OK) + _WriteKeyStoreDatabase(); + + return B_OK; +} + + +status_t +KeyStoreServer::_RequestAppAccess(const BString& keyringName, + const char* signature, const char* path, const char* accessString, + bool appIsNew, bool appWasUpdated, uint32 accessFlags, bool& allowAlways) +{ + AppAccessRequestWindow* requestWindow + = new(std::nothrow) AppAccessRequestWindow(keyringName, signature, path, + accessString, appIsNew, appWasUpdated); + if (requestWindow == NULL) + return B_NO_MEMORY; + + return requestWindow->RequestAppAccess(allowAlways); +} + + +Keyring* +KeyStoreServer::_FindKeyring(const BString& name) +{ + if (name.IsEmpty() || name == kMasterKeyringName) + return fMasterKeyring; + + return fKeyrings.BinarySearchByKey(name, &Keyring::Compare); +} + + +status_t +KeyStoreServer::_AddKeyring(const BString& name) +{ + if (_FindKeyring(name) != NULL) + return B_NAME_IN_USE; + + Keyring* keyring = new(std::nothrow) Keyring(name); + if (keyring == NULL) + return B_NO_MEMORY; + + if (!fKeyrings.BinaryInsert(keyring, &Keyring::Compare)) { + delete keyring; + return B_ERROR; + } + + return B_OK; +} + + +status_t +KeyStoreServer::_RemoveKeyring(const BString& name) +{ + Keyring* keyring = _FindKeyring(name); + if (keyring == NULL) + return B_ENTRY_NOT_FOUND; + + if (keyring == fMasterKeyring) { + // The master keyring can't be removed. + return B_NOT_ALLOWED; + } + + return fKeyrings.RemoveItem(keyring) ? B_OK : B_ERROR; +} + + +status_t +KeyStoreServer::_UnlockKeyring(Keyring& keyring) +{ + if (!keyring.HasUnlockKey()) + return keyring.Unlock(NULL); + + // If we are accessing a keyring that has been added to master access we + // get the key from the master keyring and unlock with that. + BMessage keyMessage; + if (&keyring != fMasterKeyring && fMasterKeyring->IsUnlocked()) { + if (fMasterKeyring->FindKey(kKeyringKeysIdentifier, keyring.Name(), + false, &keyMessage) == B_OK) { + // We found a key for this keyring, try to unlock with it. + if (keyring.Unlock(&keyMessage) == B_OK) + return B_OK; + } + } + + // No key, we need to request one from the user. + status_t result = _RequestKey(keyring.Name(), keyMessage); + if (result != B_OK) + return result; + + return keyring.Unlock(&keyMessage); +} + + +status_t +KeyStoreServer::_RequestKey(const BString& keyringName, BMessage& keyMessage) +{ + KeyRequestWindow* requestWindow = new(std::nothrow) KeyRequestWindow(); + if (requestWindow == NULL) + return B_NO_MEMORY; + + return requestWindow->RequestKey(keyringName, keyMessage); +} + + +int +main(int argc, char* argv[]) +{ + KeyStoreServer* app = new(std::nothrow) KeyStoreServer(); + if (app == NULL) + return 1; + + app->Run(); + delete app; + return 0; +} diff --git a/src/servers/keystore/KeyStoreServer.h b/src/servers/keystore/KeyStoreServer.h new file mode 100644 index 0000000000..4ab7a460fb --- /dev/null +++ b/src/servers/keystore/KeyStoreServer.h @@ -0,0 +1,64 @@ +/* + * Copyright 2012, Michael Lotz, mmlr@mlotz.ch. All Rights Reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _KEY_STORE_SERVER_H +#define _KEY_STORE_SERVER_H + + +#include +#include +#include +#include + + +struct app_info; +class Keyring; + +typedef BObjectList KeyringList; + + +class KeyStoreServer : public BApplication { +public: + KeyStoreServer(); +virtual ~KeyStoreServer(); + +virtual void MessageReceived(BMessage* message); + +private: + status_t _ReadKeyStoreDatabase(); + status_t _WriteKeyStoreDatabase(); + + uint32 _AccessFlagsFor(uint32 command) const; + const char* _AccessStringFor(uint32 accessFlag) const; + status_t _ResolveCallingApp(const BMessage& message, + app_info& callingAppInfo) const; + + status_t _ValidateAppAccess(Keyring& keyring, + const app_info& appInfo, + uint32 accessFlags); + status_t _RequestAppAccess( + const BString& keyringName, + const char* signature, + const char* path, + const char* accessString, bool appIsNew, + bool appWasUpdated, uint32 accessFlags, + bool& allowAlways); + + Keyring* _FindKeyring(const BString& name); + + status_t _AddKeyring(const BString& name); + status_t _RemoveKeyring(const BString& name); + + status_t _UnlockKeyring(Keyring& keyring); + + status_t _RequestKey(const BString& keyringName, + BMessage& keyMessage); + + Keyring* fMasterKeyring; + KeyringList fKeyrings; + BFile fKeyStoreFile; +}; + + +#endif // _KEY_STORE_SERVER_H diff --git a/src/servers/keystore/Keyring.cpp b/src/servers/keystore/Keyring.cpp new file mode 100644 index 0000000000..8392716909 --- /dev/null +++ b/src/servers/keystore/Keyring.cpp @@ -0,0 +1,522 @@ +/* + * Copyright 2012, Michael Lotz, mmlr@mlotz.ch. All Rights Reserved. + * Distributed under the terms of the MIT License. + */ + + +#include "Keyring.h" + + +Keyring::Keyring() + : + fHasUnlockKey(false), + fUnlocked(false), + fModified(false) +{ +} + + +Keyring::Keyring(const char* name) + : + fName(name), + fHasUnlockKey(false), + fUnlocked(false), + fModified(false) +{ +} + + +Keyring::~Keyring() +{ +} + + +status_t +Keyring::ReadFromMessage(const BMessage& message) +{ + status_t result = message.FindString("name", &fName); + if (result != B_OK) + return result; + + result = message.FindBool("hasUnlockKey", &fHasUnlockKey); + if (result != B_OK) + return result; + + ssize_t size; + const void* data; + result = message.FindData("data", B_RAW_TYPE, &data, &size); + if (result != B_OK) + return result; + + if (size < 0) + return B_ERROR; + + fFlatBuffer.SetSize(0); + ssize_t written = fFlatBuffer.WriteAt(0, data, size); + if (written != size) { + fFlatBuffer.SetSize(0); + return written < 0 ? written : B_ERROR; + } + + return B_OK; +} + + +status_t +Keyring::WriteToMessage(BMessage& message) +{ + status_t result = _EncryptToFlatBuffer(); + if (result != B_OK) + return result; + + result = message.AddData("data", B_RAW_TYPE, fFlatBuffer.Buffer(), + fFlatBuffer.BufferLength()); + if (result != B_OK) + return result; + + result = message.AddBool("hasUnlockKey", fHasUnlockKey); + if (result != B_OK) + return result; + + return message.AddString("name", fName); +} + + +status_t +Keyring::Unlock(const BMessage* keyMessage) +{ + if (fUnlocked) + return B_OK; + + if (fHasUnlockKey == (keyMessage == NULL)) + return B_BAD_VALUE; + + if (keyMessage != NULL) + fUnlockKey = *keyMessage; + + status_t result = _DecryptFromFlatBuffer(); + if (result != B_OK) { + fUnlockKey.MakeEmpty(); + return result; + } + + fUnlocked = true; + return B_OK; +} + + +void +Keyring::Lock() +{ + if (!fUnlocked) + return; + + _EncryptToFlatBuffer(); + + fUnlockKey.MakeEmpty(); + fData.MakeEmpty(); + fApplications.MakeEmpty(); + fUnlocked = false; +} + + +bool +Keyring::IsUnlocked() const +{ + return fUnlocked; +} + + +bool +Keyring::HasUnlockKey() const +{ + return fHasUnlockKey; +} + + +const BMessage& +Keyring::UnlockKey() const +{ + return fUnlockKey; +} + + +status_t +Keyring::SetUnlockKey(const BMessage& keyMessage) +{ + if (!fUnlocked) + return B_NOT_ALLOWED; + + fHasUnlockKey = true; + fUnlockKey = keyMessage; + fModified = true; + return B_OK; +} + + +status_t +Keyring::RemoveUnlockKey() +{ + if (!fUnlocked) + return B_NOT_ALLOWED; + + fUnlockKey.MakeEmpty(); + fHasUnlockKey = false; + fModified = true; + return B_OK; +} + + +status_t +Keyring::GetNextApplication(uint32& cookie, BString& signature, + BString& path) +{ + if (!fUnlocked) + return B_NOT_ALLOWED; + + char* nameFound = NULL; + status_t result = fApplications.GetInfo(B_MESSAGE_TYPE, cookie++, + &nameFound, NULL); + if (result != B_OK) + return B_ENTRY_NOT_FOUND; + + BMessage appMessage; + result = fApplications.FindMessage(nameFound, &appMessage); + if (result != B_OK) + return B_ENTRY_NOT_FOUND; + + result = appMessage.FindString("path", &path); + if (result != B_OK) + return B_ERROR; + + signature = nameFound; + return B_OK; +} + + +status_t +Keyring::FindApplication(const char* signature, const char* path, + BMessage& appMessage) +{ + if (!fUnlocked) + return B_NOT_ALLOWED; + + int32 count; + type_code type; + if (fApplications.GetInfo(signature, &type, &count) != B_OK) + return B_ENTRY_NOT_FOUND; + + for (int32 i = 0; i < count; i++) { + if (fApplications.FindMessage(signature, i, &appMessage) != B_OK) + continue; + + BString appPath; + if (appMessage.FindString("path", &appPath) != B_OK) + continue; + + if (appPath == path) + return B_OK; + } + + appMessage.MakeEmpty(); + return B_ENTRY_NOT_FOUND; +} + + +status_t +Keyring::AddApplication(const char* signature, const BMessage& appMessage) +{ + if (!fUnlocked) + return B_NOT_ALLOWED; + + status_t result = fApplications.AddMessage(signature, &appMessage); + if (result != B_OK) + return result; + + fModified = true; + return B_OK; +} + + +status_t +Keyring::RemoveApplication(const char* signature, const char* path) +{ + if (!fUnlocked) + return B_NOT_ALLOWED; + + if (path == NULL) { + // We want all of the entries for this signature removed. + status_t result = fApplications.RemoveName(signature); + if (result != B_OK) + return B_ENTRY_NOT_FOUND; + + fModified = true; + return B_OK; + } + + int32 count; + type_code type; + if (fApplications.GetInfo(signature, &type, &count) != B_OK) + return B_ENTRY_NOT_FOUND; + + for (int32 i = 0; i < count; i++) { + BMessage appMessage; + if (fApplications.FindMessage(signature, i, &appMessage) != B_OK) + return B_ERROR; + + BString appPath; + if (appMessage.FindString("path", &appPath) != B_OK) + continue; + + if (appPath == path) { + fApplications.RemoveData(signature, i); + fModified = true; + return B_OK; + } + } + + return B_ENTRY_NOT_FOUND; +} + + +status_t +Keyring::FindKey(const BString& identifier, const BString& secondaryIdentifier, + bool secondaryIdentifierOptional, BMessage* _foundKeyMessage) const +{ + if (!fUnlocked) + return B_NOT_ALLOWED; + + int32 count; + type_code type; + if (fData.GetInfo(identifier, &type, &count) != B_OK) + return B_ENTRY_NOT_FOUND; + + // We have a matching primary identifier, need to check for the secondary + // identifier. + for (int32 i = 0; i < count; i++) { + BMessage candidate; + if (fData.FindMessage(identifier, i, &candidate) != B_OK) + return B_ERROR; + + BString candidateIdentifier; + if (candidate.FindString("secondaryIdentifier", + &candidateIdentifier) != B_OK) { + candidateIdentifier = ""; + } + + if (candidateIdentifier == secondaryIdentifier) { + if (_foundKeyMessage != NULL) + *_foundKeyMessage = candidate; + return B_OK; + } + } + + // We didn't find an exact match. + if (secondaryIdentifierOptional) { + if (_foundKeyMessage == NULL) + return B_OK; + + // The secondary identifier is optional, so we just return the + // first entry. + return fData.FindMessage(identifier, 0, _foundKeyMessage); + } + + return B_ENTRY_NOT_FOUND; +} + + +status_t +Keyring::FindKey(BKeyType type, BKeyPurpose purpose, uint32 index, + BMessage& _foundKeyMessage) const +{ + if (!fUnlocked) + return B_NOT_ALLOWED; + + for (int32 keyIndex = 0;; keyIndex++) { + int32 count = 0; + char* identifier = NULL; + if (fData.GetInfo(B_MESSAGE_TYPE, keyIndex, &identifier, NULL, + &count) != B_OK) { + break; + } + + if (type == B_KEY_TYPE_ANY && purpose == B_KEY_PURPOSE_ANY) { + // No need to inspect the actual keys. + if ((int32)index >= count) { + index -= count; + continue; + } + + return fData.FindMessage(identifier, index, &_foundKeyMessage); + } + + // Go through the keys to check their type and purpose. + for (int32 subkeyIndex = 0; subkeyIndex < count; subkeyIndex++) { + BMessage subkey; + if (fData.FindMessage(identifier, subkeyIndex, &subkey) != B_OK) + return B_ERROR; + + bool match = true; + if (type != B_KEY_TYPE_ANY) { + BKeyType subkeyType; + if (subkey.FindUInt32("type", (uint32*)&subkeyType) != B_OK) + return B_ERROR; + + match = subkeyType == type; + } + + if (match && purpose != B_KEY_PURPOSE_ANY) { + BKeyPurpose subkeyPurpose; + if (subkey.FindUInt32("purpose", (uint32*)&subkeyPurpose) + != B_OK) { + return B_ERROR; + } + + match = subkeyPurpose == purpose; + } + + if (match) { + if (index == 0) { + _foundKeyMessage = subkey; + return B_OK; + } + + index--; + } + } + } + + return B_ENTRY_NOT_FOUND; +} + + +status_t +Keyring::AddKey(const BString& identifier, const BString& secondaryIdentifier, + const BMessage& keyMessage) +{ + if (!fUnlocked) + return B_NOT_ALLOWED; + + // Check for collisions. + if (FindKey(identifier, secondaryIdentifier, false, NULL) == B_OK) + return B_NAME_IN_USE; + + // We're fine, just add the new key. + status_t result = fData.AddMessage(identifier, &keyMessage); + if (result != B_OK) + return result; + + fModified = true; + return B_OK; +} + + +status_t +Keyring::RemoveKey(const BString& identifier, + const BMessage& keyMessage) +{ + if (!fUnlocked) + return B_NOT_ALLOWED; + + int32 count; + type_code type; + if (fData.GetInfo(identifier, &type, &count) != B_OK) + return B_ENTRY_NOT_FOUND; + + for (int32 i = 0; i < count; i++) { + BMessage candidate; + if (fData.FindMessage(identifier, i, &candidate) != B_OK) + return B_ERROR; + + // We require an exact match. + if (!candidate.HasSameData(keyMessage)) + continue; + + status_t result = fData.RemoveData(identifier, i); + if (result != B_OK) + return result; + + fModified = true; + return B_OK; + } + + return B_ENTRY_NOT_FOUND; +} + + +int +Keyring::Compare(const Keyring* one, const Keyring* two) +{ + return strcmp(one->Name(), two->Name()); +} + + +int +Keyring::Compare(const BString* name, const Keyring* keyring) +{ + return strcmp(name->String(), keyring->Name()); +} + + +status_t +Keyring::_EncryptToFlatBuffer() +{ + if (!fModified) + return B_OK; + + if (!fUnlocked) + return B_NOT_ALLOWED; + + BMessage container; + status_t result = container.AddMessage("data", &fData); + if (result != B_OK) + return result; + + result = container.AddMessage("applications", &fApplications); + if (result != B_OK) + return result; + + fFlatBuffer.SetSize(0); + fFlatBuffer.Seek(0, SEEK_SET); + + result = container.Flatten(&fFlatBuffer); + if (result != B_OK) + return result; + + if (fHasUnlockKey) { + // TODO: Actually encrypt the flat buffer... + } + + fModified = false; + return B_OK; +} + + +status_t +Keyring::_DecryptFromFlatBuffer() +{ + if (fFlatBuffer.BufferLength() == 0) + return B_OK; + + if (fHasUnlockKey) { + // TODO: Actually decrypt the flat buffer... + } + + BMessage container; + fFlatBuffer.Seek(0, SEEK_SET); + status_t result = container.Unflatten(&fFlatBuffer); + if (result != B_OK) + return result; + + result = container.FindMessage("data", &fData); + if (result != B_OK) + return result; + + result = container.FindMessage("applications", &fApplications); + if (result != B_OK) { + fData.MakeEmpty(); + return result; + } + + return B_OK; +} diff --git a/src/servers/keystore/Keyring.h b/src/servers/keystore/Keyring.h new file mode 100644 index 0000000000..de8d931ccd --- /dev/null +++ b/src/servers/keystore/Keyring.h @@ -0,0 +1,76 @@ +/* + * Copyright 2012, Michael Lotz, mmlr@mlotz.ch. All Rights Reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _KEYRING_H +#define _KEYRING_H + + +#include +#include + + +class Keyring { +public: + Keyring(); + Keyring(const char* name); + ~Keyring(); + + const char* Name() const { return fName; } + status_t ReadFromMessage(const BMessage& message); + status_t WriteToMessage(BMessage& message); + + status_t Unlock(const BMessage* keyMessage); + void Lock(); + bool IsUnlocked() const; + + bool HasUnlockKey() const; + const BMessage& UnlockKey() const; + + status_t SetUnlockKey(const BMessage& keyMessage); + status_t RemoveUnlockKey(); + + status_t GetNextApplication(uint32& cookie, + BString& signature, BString& path); + status_t FindApplication(const char* signature, + const char* path, BMessage& appMessage); + status_t AddApplication(const char* signature, + const BMessage& appMessage); + status_t RemoveApplication(const char* signature, + const char* path); + + status_t FindKey(const BString& identifier, + const BString& secondaryIdentifier, + bool secondaryIdentifierOptional, + BMessage* _foundKeyMessage) const; + status_t FindKey(BKeyType type, BKeyPurpose purpose, + uint32 index, + BMessage& _foundKeyMessage) const; + + status_t AddKey(const BString& identifier, + const BString& secondaryIdentifier, + const BMessage& keyMessage); + status_t RemoveKey(const BString& identifier, + const BMessage& keyMessage); + +static int Compare(const Keyring* one, + const Keyring* two); +static int Compare(const BString* name, + const Keyring* keyring); + +private: + status_t _EncryptToFlatBuffer(); + status_t _DecryptFromFlatBuffer(); + + BString fName; + BMallocIO fFlatBuffer; + BMessage fData; + BMessage fApplications; + BMessage fUnlockKey; + bool fHasUnlockKey; + bool fUnlocked; + bool fModified; +}; + + +#endif // _KEYRING_H diff --git a/src/servers/keystore/keystore_server.rdef b/src/servers/keystore/keystore_server.rdef new file mode 100644 index 0000000000..b92601b5c5 --- /dev/null +++ b/src/servers/keystore/keystore_server.rdef @@ -0,0 +1,13 @@ +resource app_signature "application/x-vnd.Haiku-keystore_server"; + +resource app_flags B_EXCLUSIVE_LAUNCH | B_BACKGROUND_APP; + +resource app_version { + major = 1, + middle = 0, + minor = 0, + variety = B_APPV_ALPHA, + internal = 0, + short_info = "keystore_server", + long_info = "keystore_server ©2012 Haiku, Inc." +}; diff --git a/src/servers/notification/AppGroupView.cpp b/src/servers/notification/AppGroupView.cpp index 450476f80a..0927d16426 100644 --- a/src/servers/notification/AppGroupView.cpp +++ b/src/servers/notification/AppGroupView.cpp @@ -23,7 +23,7 @@ #include "NotificationView.h" -static const int kHeaderSize = 20; +static const int kHeaderSize = 23; AppGroupView::AppGroupView(NotificationWindow* win, const char* label) @@ -61,13 +61,15 @@ AppGroupView::Draw(BRect updateRect) // Draw the buttons fCollapseRect.top = (kHeaderSize - kExpandSize) / 2; - fCollapseRect.left = kEdgePadding * 2; + fCollapseRect.left = kEdgePadding * 3; fCollapseRect.right = fCollapseRect.left + 1.5 * kExpandSize; fCollapseRect.bottom = fCollapseRect.top + kExpandSize; fCloseRect = bounds; - fCloseRect.top = (kHeaderSize - kExpandSize) / 2; - fCloseRect.right -= kEdgePadding * 2; + fCloseRect.top = (kHeaderSize - kCloseSize) / 2; + // Take off the 1 to line this up with the close button on the + // notification view + fCloseRect.right -= kEdgePadding * 3 - 1; fCloseRect.left = fCloseRect.right - kCloseSize; fCloseRect.bottom = fCloseRect.top + kCloseSize; @@ -88,9 +90,13 @@ AppGroupView::Draw(BRect updateRect) label << " (" << fInfo.size() << ")"; SetFont(be_bold_font); + font_height fontHeight; + GetFontHeight(&fontHeight); + float y = (bounds.top + bounds.bottom - ceilf(fontHeight.ascent) + - ceilf(fontHeight.descent)) / 2.0 + ceilf(fontHeight.ascent); - DrawString(label.String(), BPoint(fCollapseRect.right + 2 * kEdgePadding, - fCloseRect.bottom)); + DrawString(label.String(), + BPoint(fCollapseRect.right + 4 * kEdgePadding, y)); } @@ -98,11 +104,7 @@ void AppGroupView::_DrawCloseButton(const BRect& updateRect) { PushState(); - BRect closeRect = Bounds(); - - closeRect.InsetBy(7, 7); - closeRect.left = closeRect.right - kCloseSize; - closeRect.bottom = closeRect.top + kCloseSize; + BRect closeRect = fCloseRect; rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR); float tint = B_DARKEN_2_TINT; @@ -225,6 +227,13 @@ AppGroupView::AddInfo(NotificationView* view) } } + // Invalidate all children to show or hide the close buttons in the + // notification view + int32 children = fInfo.size(); + for (int32 i = 0; i < children; i++) { + fInfo[i]->Invalidate(); + } + if (!found) { fInfo.push_back(view); } @@ -249,3 +258,10 @@ AppGroupView::HasChildren() { return !fInfo.empty(); } + + +int32 +AppGroupView::ChildrenCount() +{ + return fInfo.size(); +} diff --git a/src/servers/notification/AppGroupView.h b/src/servers/notification/AppGroupView.h index 10f9e60cc2..c3cbeac18e 100644 --- a/src/servers/notification/AppGroupView.h +++ b/src/servers/notification/AppGroupView.h @@ -29,6 +29,7 @@ public: void Draw(BRect updateRect); bool HasChildren(); + int32 ChildrenCount(); void AddInfo(NotificationView* view); diff --git a/src/servers/notification/NotificationView.cpp b/src/servers/notification/NotificationView.cpp index f5a2994fe2..b88e5de99f 100644 --- a/src/servers/notification/NotificationView.cpp +++ b/src/servers/notification/NotificationView.cpp @@ -29,6 +29,7 @@ #include #include +#include "AppGroupView.h" #include "NotificationWindow.h" @@ -273,7 +274,9 @@ NotificationView::Draw(BRect updateRect) rgb_color detailCol = ui_color(B_CONTROL_BORDER_COLOR); detailCol = tint_color(detailCol, B_LIGHTEN_2_TINT); - _DrawCloseButton(updateRect); + AppGroupView* groupView = dynamic_cast(Parent()); + if (groupView != NULL && groupView->ChildrenCount() > 1) + _DrawCloseButton(updateRect); SetHighColor(tint_color(ViewColor(), B_DARKEN_1_TINT)); BPoint left(Bounds().left, Bounds().top); diff --git a/src/servers/notification/NotificationWindow.cpp b/src/servers/notification/NotificationWindow.cpp index 068048bee3..73053e2058 100644 --- a/src/servers/notification/NotificationWindow.cpp +++ b/src/servers/notification/NotificationWindow.cpp @@ -376,11 +376,11 @@ NotificationWindow::SetPosition() break; case B_DESKBAR_RIGHT_TOP: x = frame.left - width - rightOffset; - y = frame.top - topOffset; + y = frame.top - topOffset + 1; break; case B_DESKBAR_LEFT_TOP: x = frame.right + leftOffset; - y = frame.top - topOffset; + y = frame.top - topOffset + 1; break; case B_DESKBAR_RIGHT_BOTTOM: y = frame.bottom - height + bottomOffset;